{"id":374802,"date":"2024-05-21T06:09:18","date_gmt":"2024-05-21T06:09:18","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=374802"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=374802","title":{"rendered":"<span>\u0420\u0443\u043b\u0438\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u043e\u043c Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 Airflow \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0441\u0430\u043c\u043e\u043f\u0438\u0441\u043d\u043e\u0433\u043e \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/509\/407\/045\/509407045a2c4cd8016dadee1577a38a.png\" width=\"2561\" height=\"1261\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/509\/407\/045\/509407045a2c4cd8016dadee1577a38a.png\"\/><\/figure>\n<p>Airflow \u0432 Lamoda Tech \u0438\u0433\u0440\u0430\u0435\u0442 \u0440\u043e\u043b\u044c \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c 1 800+ \u0442\u0430\u0441\u043e\u043a \u043d\u0430 \u043f\u0440\u043e\u0434\u0435, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0412\u0441\u0435 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0430\u0431\u043c\u0438\u0442\u044f\u0442\u0441\u044f \u0438\u0437 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432. \u0418 \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439: \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0445 \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u043c\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043d\u0434\u0440\u0435\u0439 \u0411\u0443\u043b\u0433\u0430\u043a\u043e\u0432, \u044f \u043b\u0438\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 Big Data \u0432 Lamoda Tech. \u0412\u043c\u0435\u0441\u0442\u0435 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u0418\u0432\u0430\u043d\u043e\u043c \u0412\u0430\u0441\u0435\u043d\u043a\u043e\u0432\u044b\u043c <a class=\"mention\" href=\"\/users\/vasenkovid\">@vasenkovid<\/a> \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Airflow-\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<h2>\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043d\u0430\u0448\u0438 Airflow \u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u044b<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0445\u043e\u0447\u0443 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e \u043d\u0430\u0448 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u0432 Airflow. \u042d\u0442\u043e \u0434\u0430\u0441\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u0432\u0435\u0440\u0445\u0443.\u00a0<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u044b \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u044b \u0443\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u0432 <a href=\"https:\/\/habr.com\/ru\/companies\/lamoda\/articles\/518620\/\"><u>\u0441\u0442\u0430\u0442\u044c\u0435<\/u><\/a>. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u044d\u0442\u043e\u0439 \u0442\u0435\u043c\u043e\u0439, \u0431\u043b\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u043f\u0440\u043e \u043d\u0430\u0448 Airflow. \u0412 PROD-\u043a\u043e\u043d\u0442\u0443\u0440\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 370+ \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0434\u0430\u0433\u043e\u0432 (DAG \u2014 Directed Acyclic Graph), \u0430 \u0432 DEV-\u043a\u043e\u043d\u0442\u0443\u0440\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 Big Data, \u0434\u0430\u0442\u0430-\u0441\u0430\u0439\u0435\u043d\u0442\u0438\u0441\u0442\u043e\u0432 \u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u043e\u0432 \u043d\u0430 \u0441\u0432\u043e\u0438\u0445 \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442 \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043a\u0430\u0442\u043e\u043c \u043d\u0430 PROD.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b13\/994\/a11\/b13994a111316d868dc8c2314c659fa0.png\" width=\"2561\" height=\"1261\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b13\/994\/a11\/b13994a111316d868dc8c2314c659fa0.png\"\/><\/figure>\n<p>\u041f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0441\u0432\u043e\u044f \u0432\u0435\u0442\u043a\u0430 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0432\u043d\u0435\u0441\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 master-\u0432\u0435\u0442\u043a\u0443, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0443\u044e \u0437\u0430 PROD, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 merge \u0432 \u0432\u0435\u0442\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 DEV-\u043a\u043e\u043d\u0442\u0443\u0440\u0435.<\/p>\n<p>\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 Airflow, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0435\u0437\u0434\u0430. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f Airflow 2.7.3 \u043d\u0430 Celery Executor.<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u043c\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u0433\u0438 \u043d\u0435 \u0432 \u043a\u043e\u0434\u0435, \u0430 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445.\u00a0<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0430\u0435\u043c \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <a href=\"https:\/\/github.com\/lightbend\/config\/blob\/master\/HOCON.md\"><u>HOCON<\/u><\/a> (Human-Optimized Config Object Notation) \u2014 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c \u0432\u0435\u0440\u0441\u0438\u0438 JSON. \u0421\u0440\u0435\u0434\u0438 <a href=\"https:\/\/github.com\/lightbend\/config\/blob\/master\/HOCON.md#goals--background\"><u>\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 HOCON<\/u><\/a> \u0434\u043b\u044f \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441,<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 HOCON-\u0444\u0430\u0439\u043b\u043e\u0432,\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0430. \u0412 \u043d\u0438\u0445 \u0432\u0445\u043e\u0434\u044f\u0442 <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow\/stable\/_api\/airflow\/models\/dag\/index.html#airflow.models.dag.DAG\"><u>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u0430\u0433\u0430<\/u><\/a>, \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u043e \u043f\u043e\u0447\u0442\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u043e \u0435\u0433\u043e \u043f\u0430\u0434\u0435\u043d\u0438\u0438. \u0422\u0430\u043a\u0436\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0434\u0435\u0436\u0443\u0440\u043d\u043e\u043c\u0443 \u0434\u0430\u0442\u0430-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0443, \u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u044b \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0430.<\/p>\n<pre><code class=\"python\">include \"..\/..\/generics\/emails.conf\"  dags {   main_pa_metrics {     owner = \"RND-PA\"     name = \"main_pa_metrics\"     start_date = \"20220327\"     emails = ${PRODUCT_ANALYSTS_TEAM}     schedule_interval = \"30 9 * * *\"     catchup = true     notify_on_failure = {       title = \"{dag_id} FAILED\",       message = \"\u0423\u043f\u0430\u043b \u0440\u0430\u0441\u0447\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0438 \u0432 \u043a\u043e\u043d\u0444\u043b\u044e\u0435\u043d\u0441. \u0412\u0430\u0436\u043d\u043e \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0434\u043e 12 \u0434\u043d\u044f.\",       to = {         pachca = [{           connection= \"pachca_alerts_etl\"         }, {           connection= \"pachca_alerts_pa_automation\"         }]       }     }    description = \"\u0414\u0430\u0433 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b pa_db.main_pa_metrics \u0441 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a\"   tags = [       \"critical\", \"pa\"     ] <\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0434\u0432\u0430 \u0448\u0430\u0433\u0430: \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0432 Oracle \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 Trino. <\/p>\n<pre><code class=\"python\">    tasks {       await_visitor_activity_ready {         type = \"oracle_sensor\"         sensor_type = \"job_code\"         conn_id = \"dwh\"         job_code = \"ORA_VISITOR_ACTIVITY\"         dt = \"{{ ds_nodash }}\"       }       load_trino {         type = \"trino\"         sql_params {           hive_schema = \"{{ var.value.HIVE_DB_PA }}\"           start_dt = \"{{ ds }}\"           end_dt = \"{{ next_ds }}\"         }         sql_file = \"trino\/main_pa_metrics.sql\"       }       task_order = [         \"await_visitor_activity_ready\",         \"load_trino\"       ]     }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0443\u0436\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0430\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0441\u0442\u0435\u043d\u0434\u0430 Airflow \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u0447\u0435\u0440\u0435\u0437 Jinja-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow\/stable\/templates-ref.html\"><u>\u043c\u0430\u043a\u0440\u043e\u0441\u044b, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d\u044b<\/u><\/a>:<\/p>\n<ul>\n<li>\n<p>\u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0441\u043a\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u043d \u0434\u043b\u044f Oracle, \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0430\u0442\u0443, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c;\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0442\u0430\u0441\u043a\u0435 \u2014 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043a\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441.\u00a0\u00a0<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u0441\u043e\u043a \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0441\u043f\u0438\u0441\u043a\u0430. \u041c\u043e\u0436\u043d\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u0434\u0430\u0433\u0430 \u0446\u0435\u043b\u0438\u043a\u043e\u043c<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">include \"..\/..\/generics\/emails.conf\"  dags {   main_pa_metrics {     owner = \"RND-PA\"     name = \"main_pa_metrics\"     start_date = \"20220327\"     emails = ${PRODUCT_ANALYSTS_TEAM}     schedule_interval = \"30 9 * * *\"     catchup = true     notify_on_failure = {       title = \"{dag_id} FAILED\",       message = \"\u0423\u043f\u0430\u043b \u0440\u0430\u0441\u0447\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0438 \u0432 \u043a\u043e\u043d\u0444\u043b\u044e\u0435\u043d\u0441. \u0412\u0430\u0436\u043d\u043e \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0434\u043e 12 \u0434\u043d\u044f.\",       to = {         pachca = [{           connection= \"pachca_alerts_etl\"         }, {           connection= \"pachca_alerts_pa_automation\"         }]       }     }     description = \"\u0414\u0430\u0433 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b pa_db.main_pa_metrics \u0441 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a\"     tags = [       \"critical\", \"pa\"     ]     tasks {       await_visitor_activity_ready {         type = \"oracle_sensor\"         sensor_type = \"job_code\"         conn_id = \"dwh\"         job_code = \"ORA_VISITOR_ACTIVITY\"         dt = \"{{ ds_nodash }}\"       }       load_trino {         type = \"trino\"         sql_params {           hive_schema = \"{{ var.value.HIVE_DB_PA }}\"           start_dt = \"{{ ds }}\"           end_dt = \"{{ next_ds }}\"         }         sql_file = \"trino\/main_pa_metrics.sql\"       }       task_order = [         \"await_visitor_activity_ready\",         \"load_trino\"       ]     }   } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u0433, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0430\u0441\u043e\u043a.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/d07\/2c8\/cd8\/d072c8cd837f9d1b76c91d5ac020c2b3.png\" width=\"1600\" height=\"907\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/d07\/2c8\/cd8\/d072c8cd837f9d1b76c91d5ac020c2b3.png\"\/><\/figure>\n<h2>\u041a\u0430\u043a \u043c\u044b \u0432\u0430\u0440\u0438\u043c Spark<\/h2>\n<p>\u0412 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 Lamoda Tech \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u00ab\u0434\u043e\u043a\u0435\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439\u00bb Spark. Docker \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435, \u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a \u043c\u0430\u0448\u0438\u043d\u0435, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f Spark, \u2014 \u044d\u0442\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043d\u0430 \u043d\u0435\u0439 Docker.<\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark. \u041d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u044b \u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043e\u0431\u0440\u0430\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435. \u0412 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0437\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 Spark, \u043a\u043e\u043d\u0444\u0438\u0433\u0438 Hadoop \u0438 \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430:<\/p>\n<pre><code class=\"lua\">FROM docker-registry.lamoda.ru\/centos:7.9.2009   # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Python \u0438 OpenJDK RUN yum install -y curl python3-3.6.8 java-1.8.0-openjdk &amp;&amp; \\   yum clean all &amp;&amp; \\   rm -rf \/var\/cache\/yum   # \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 Spark COPY build\/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \".\/\" RUN tar -xzf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz &amp;&amp; \\   mv spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION} $SPARK_HOME &amp;&amp; \\   rm spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz ENV PATH $SPARK_HOME\/bin:$PATH   # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0438 COPY configs\/datalake\/hadoop\/conf \/opt\/hadoop\/conf COPY [\"configs\/spark-defaults.conf\", \"configs\/spark-env.sh\", \"configs\/log4j.properties\", \"$SPARK_HOME\/conf\/\"]   # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f ENV HADOOP_CONF_DIR \/opt\/hadoop\/conf ENV YARN_CONF_DIR \/opt\/hadoop\/conf ENV HIVE_CONF_DIR \/opt\/hadoop\/conf   # \u0417\u0430\u0434\u0430\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0435 jvm options \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b ENV SPARK_JVM_OPTS \"-Dhdp.version=current -XX:+UseNUMA -XX:+UseG1GC\"   ENTRYPOINT [\"\/bin\/bash\"]<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0437:<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Scala\/Java, \u0442\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 JAR \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430 Python, \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f PySpark-\u043a\u043e\u0434\u0430.\u00a0<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 Scala\/Java:<\/p>\n<pre><code class=\"lua\"># \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 (\u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435) FROM docker-registry.lamoda.ru\/base\/lmd-spark:3.3.1-51   # \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0437 jar \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c COPY target\/scala-2.12\/aerospike-loader.jar \/aerospike-loader.jar   ENTRYPOINT [\"\/bin\/bash\"]<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 Python:<\/p>\n<pre><code class=\"lua\"># \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 (\u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435) FROM docker-registry.lamoda.ru\/base\/lmd-spark:3.3.1-51   COPY . \/tmp\/build\/   # \u043f\u0430\u043a\u0443\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 RUN python3.6 -m venv tmp_venv --clear &amp;&amp; \\ . tmp_venv\/bin\/activate &amp;&amp; \\ python3.6 -m pip install pip==21.3.1 &amp;&amp; \\ pip install -r \/tmp\/build\/requirements.txt &amp;&amp; \\ deactivate &amp;&amp; \\ cd tmp_venv &amp;&amp; \\ zip -rq \/app\/dependencies.zip * &amp;&amp; \\ rm -rf \/tmp\/build \/app\/tmp_venv   # \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f COPY py_scripts \/app\/py_scripts   ENTRYPOINT [\"\/bin\/bash\"] <\/code><\/pre>\n<p>\u0421\u0430\u0431\u043c\u0438\u0442\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0447\u0435\u0440\u0435\u0437 YARN.\u00a0<\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e Spark \u0432 Docker \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0435\u0437\u0434\u0435 \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Spark \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0430\u043f\u0433\u0440\u0435\u0439\u0434 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 Hadoop \u0438 \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442 \u043b\u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0447\u0430\u0441\u0442\u0438\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u0440\u043e\u0434 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0443: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c. \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0432\u044c\u044e, \u043d\u0430\u0436\u0430\u0442\u044c \u0430\u043f\u0440\u0443\u0432, \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0431\u0435\u0436\u0438\u0442 \u0432 Airflow \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u043c\u0435\u0442\u044c Docker, \u0447\u0442\u043e\u0431\u044b \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437\u044b \u0438 \u0442\u0430\u043a \u0436\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>Kuber Friendly: \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Kubernetes (\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u0438 \u043f\u0440\u0438 \u043f\u0438\u043b\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Spark on K8s).<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0440\u0441\u0438\u0439 Spark \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a: \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Spark \u0432 docker-\u043e\u0431\u0440\u0430\u0437\u0435 \u0438\u0437 Airflow\u00a0 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.\u00a0<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0434\u0435\u0440\u0436\u0438\u043c Spark \u0432 Docker \u0438 \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark \u043d\u0430 \u0432\u043e\u0440\u043a\u0435\u0440\u044b Airflow, \u0442\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow-providers-apache-spark\/stable\/index.html\"><u>Airflow Spark Provider<\/u><\/a> SparkSubmitOperator, SparkJDBCOperator \u0438 SparkSqlOperator. \u0422\u043e\u0447\u043d\u043e \u0442\u0430\u043a \u0436\u0435 \u043d\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u0441\u044f \u043f\u0440\u043e\u0441\u0442\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043a\u043e\u0434 \u043d\u0430 PySpark \u0447\u0435\u0440\u0435\u0437 PythonOperator \u0438\u043b\u0438 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0438\u0442\u044c spark-submit \u0447\u0435\u0440\u0435\u0437 BashOpertator.<\/p>\n<p>\u041c\u044b \u0440\u0435\u0448\u0438\u043b\u0438 \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow-providers-docker\/stable\/_api\/airflow\/providers\/docker\/operators\/docker\/index.html#airflow.providers.docker.operators.docker.DockerOperator\"><u>DockerOperator<\/u><\/a> \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432 \u0432 Airflow. \u041e\u043d \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow-providers-docker\/stable\/index.html\"><u>Airflow Docker Provider<\/u><\/a>. DockerOperator \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u0434\u0430\u0433 \u0442\u0430\u0441\u043a\u0443, \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043d\u0430 \u0432\u043e\u0440\u043a\u0435\u0440\u0435 Airflow \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0434\u043d\u044f\u0442 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430.<\/p>\n<p>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043e\u0441\u043d\u043e\u0432\u0435 DockerOperator \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<ol>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0437 \u043f\u0440\u0438 \u0441\u0431\u043e\u0440\u043a\u0435 .sh \u0444\u0430\u0439\u043b \u0441 \u043a\u043e\u0434\u043e\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u0430 <a href=\"https:\/\/spark.apache.org\/docs\/latest\/submitting-applications.html\"><u>spark-submit<\/u><\/a>. \u0412 \u043d\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, JAR \u0438\u043b\u0438 Python-\u0444\u0430\u0439\u043b, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041d\u0430\u0437\u044b\u0432\u0430\u0435\u043c \u0435\u0433\u043e, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, submit.sh. \u041f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432 \u043d\u0435\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0438\u0437 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c\u0438 \u0432 Bash.<\/p>\n<\/li>\n<\/ol>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0441\u043a\u0440\u0438\u043f\u0442\u0430 spark-submit \u0432 \u043a\u043e\u0434\u0431\u043b\u043e\u043a\u0435:<\/p>\n<pre><code class=\"bash\">spark-submit \\ --master \"yarn\" \\ --queue \"apps\" \\ --deploy-mode \"cluster\" \\ --class \"tech.lamoda.dwh.etl.executor.spark_sql.SparkSqlExecutor\" \\ --name \"ip_geo_snapshot\" \\ --driver-cores \"1\" \\ --driver-memory \"2G\" \\ --executor-cores \"1\" \\ --executor-memory \"1G\" \\ --num-executors \"3\" \\ --files \"\/app\/metrics.conf\" \\ --conf \"spark.yarn.maxAppAttempts=1\" \\ --conf \"spark.driver.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.executor.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.yarn.am.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.metrics.conf=metrics.conf\" \\ --conf \"spark.metrics.namespace=ip_geo\" \\ --conf \"spark.sql.broadcastTimeout=1200\" \\ \/data-processing-etl.jar \\ --out-db \"$OUT_DB\" \\ --out-table \"$OUT_TABLE\" \\ --mode \"$MODE\" \\ --partitions-num \"$PARTITIONS_NUM\" \\ \u2014-partitions-cols \"$PARTITIONS_COLS\" \\ --sql \"$SQL\" <\/code><\/pre>\n<ol start=\"2\">\n<li>\n<p>\u0412 \u043a\u043e\u043d\u0444\u0438\u0433 \u0434\u0430\u0433\u0430 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0442\u0430\u0441\u043a\u0443, \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0449\u0443\u044e DockerOperator:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">ip_geo_snapshot {   type = \"docker\"   image = ${data-processing-etl-spark3.3}   command = \".\/submit.sh\" # \u043f\u0443\u0442\u044c \u0432 \u043e\u0431\u0440\u0430\u0437\u0435 \u0434\u043e .sh \u0444\u0430\u0439\u043b\u0430   environment { # \u0441\u043b\u043e\u0432\u0430\u0440\u044c env \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0431\u0443\u0434\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432 \u043a\u043e\u0434 spark-submit \u043f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430     OUT_DB = \"{{ var.value.HIVE_DB_DERIVATIVES }}\"     OUT_TABLE = \"ip_geo_snapshot\"     MODE = \"overwrite\"     PARTITIONS_NUM = \"1     PARTITIONS_COLS = \"dt\"     SQL = \"\"\"{{ sql('spark\/ip_geo_snapshot.sql', params={       'ds_nodash': ds_nodash,       'hive_db_derivatives': var.value.HIVE_DB_DERIVATIVES      }) }}\"\"\"   } }<\/code><\/pre>\n<ol start=\"3\">\n<li>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u044b\u0437\u043e\u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043f\u0440\u043e\u0438\u0437\u043e\u0439\u0434\u0435\u0442 \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"python\">new_task = DockerOperator(    dag=dag,    task_id=\"ip_geo_snapshot\",    image=\"docker-registry.lamoda.ru\/data-processing-etl:1.0.0\",    environment=**environment,    auto_remove=\"success\",    command=\".\/submit.sh\" )<\/code><\/pre>\n<p>\u041d\u043e \u0443 \u0442\u0430\u043a\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u0438\u0441\u044c \u0441\u0432\u043e\u0438 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043a\u0438:<\/p>\n<ul>\n<li>\n<p>\u041f\u043e \u043a\u043e\u0434\u0443 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f \u0441 \u0434\u0430\u0433\u0430\u043c\u0438 \u0437\u0430\u0447\u0430\u0441\u0442\u0443\u044e \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0434\u0430\u043d\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044e \u0438 \u043a\u0430\u043a\u0438\u0435 \u0435\u0449\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f. \u0417\u0430 \u0431\u0435\u0437\u043e\u0431\u0438\u0434\u043d\u044b\u043c \u0441 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0432\u0437\u0433\u043b\u044f\u0434\u0430 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435\u043c <code>command = \".\/submit.sh\"<\/code> \u043c\u043e\u0436\u0435\u0442 \u0441\u043a\u0440\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u0447\u0442\u043e-\u0442\u043e \u0432\u0440\u043e\u0434\u0435 num-executors=100500 \u0438\u043b\u0438 executor-memory=2TB<\/p>\n<\/li>\n<li>\n<p>\u041d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043e\u0435\u0437\u0436\u0430\u044e\u0442 \u0434\u043e \u043f\u0440\u043e\u0434\u0430 \u043c\u0438\u043d\u0438\u043c\u0443\u043c \u0447\u0435\u0440\u0435\u0437 2 \u043f\u0443\u043b\u043b-\u0440\u0435\u043a\u0432\u0435\u0441\u0442\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0447\u0442\u043e\u0431\u044b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 spark-submit \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>\"spark.sql.adaptive.coalescePartitions.initialPartitionNum\" = \"1000\"<\/code>, \u043d\u0443\u0436\u043d\u043e \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u043e\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0444\u0430\u0439\u043b <code>submit.sh<\/code> \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0430\u043c\u0438 \u0434\u0430\u0433\u043e\u0432 \u0432\u0435\u0440\u0441\u0438\u044e \u043e\u0431\u0440\u0430\u0437\u0430, \u043f\u043e\u043b\u0443\u0447\u0438\u0432\u0448\u0435\u0433\u043e\u0441\u044f \u043d\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0448\u0430\u0433\u0435.<\/p>\n<\/li>\n<\/ul>\n<p>\u0411\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark \u0431\u0435\u0437 \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u043e\u043a \u043c\u044b \u043d\u0430\u0439\u0442\u0438 \u043d\u0435 \u0441\u043c\u043e\u0433\u043b\u0438. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f22\/e82\/191\/f22e821911d64da7c72b81eee8d2e533.png\" width=\"2561\" height=\"1261\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f22\/e82\/191\/f22e821911d64da7c72b81eee8d2e533.png\"\/><\/figure>\n<h2>\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043d\u0430\u0448\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u0435<\/h2>\n<p>\u041c\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 \u043d\u043e\u0432\u044b\u0439 Airflow-\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0438\u043c\u0435\u0435\u0442 \u043f\u0440\u043e\u0431\u043b\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u0438 \u0440\u0435\u0448\u0430\u0435\u0442 \u043d\u0430\u0448\u0438 \u0437\u0430\u0434\u0430\u0447\u0438. \u0423\u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043b\u0438 \u0435\u0433\u043e \u043e\u0442 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e DockerOperator \u2014 \u0438 \u043d\u0430\u0437\u0432\u0430\u043b\u0438 SparkSubmitDockerOperator.<\/p>\n<p>\u041f\u0440\u0438 \u0435\u0433\u043e \u0432\u044b\u0437\u043e\u0432\u0435 \u0432 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u043f\u0435\u0440\u0435\u0434\u0430\u044e\u0442\u0441\u044f \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0418\u0437 \u043d\u0438\u0445 \u043c\u043e\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 spark-submit \u0438 \u0434\u0430\u043b\u044c\u0448\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0435\u0435 \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.\u00a0<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0442\u0430\u043a\u0436\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0435 \u0444\u0443\u043d\u043a\u0446\u0438\u0438, \u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u0432 \u044d\u0442\u043e\u043c \u0440\u0430\u0437\u0434\u0435\u043b\u0435.<\/p>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u00a0<\/h3>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u0430\u044f \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f \u0442\u0430\u0441\u043a\u0438 \u043f\u0440\u0438 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0438\u0438 SparkSubmitDockerOperator \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"python\">ip_geo_snapshot {   image = ${data-processing-etl-spark3.3}   type = \"spark_submit_v2\"     spark-params = {     driver-cores = 1     driver-memory = 2G     executor-cores = 1     executor-memory = 1G     num-executors = 3     files = \"\/app\/metrics.conf\"     class = \"tech.lamoda.dwh.etl.executor.spark_sql.SparkSqlExecutor\"     conf {       \"spark.metrics.conf\" = \"metrics.conf\"       \"spark.metrics.namespace\" = \"ip_geo\"    \"spark.sql.broadcastTimeout\" = \"1200\"     }   }   program-path = \"\/data-processing-etl.jar\"   job-params {     out-db = \"{{ var.value.HIVE_DB_DERIVATIVES }}\"     out-table = \"ip_geo_snapshot\"     mode = \"overwrite\"     partitions-num = 1     partitions-cols = \"dt\"     sql = \"\"\"{{ sql('spark\/ip_geo_snapshot.sql', params={       'ds_nodash': ds_nodash,       'hive_db_derivatives': var.value.HIVE_DB_DERIVATIVES      }) }}\"\"\"   }     spark-files {     \"\/app\/metrics.conf\" = \"\"\"     master.source.jvm.class=org.apache.spark.metrics.source.JvmSource     worker.source.jvm.class=org.apache.spark.metrics.source.JvmSource     driver.source.jvm.class=org.apache.spark.metrics.source.JvmSource     executor.source.jvm.class=org.apache.spark.metrics.source.JvmSource       *.sink.statsd.class=org.apache.spark.metrics.sink.StatsdSink     *.sink.statsd.prefix={{ var.value.STATSD_PREFIX_BATCH }}     *.sink.statsd.period=10     *.sink.statsd.unit=seconds     *.sink.statsd.host={{ var.value.STATSD_HOST }}     *.sink.statsd.port={{ var.value.STATSD_PORT }}     \"\"\"   } }<\/code><\/pre>\n<p>\u042d\u0442\u0438 \u0431\u043b\u043e\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u044b \u0432 \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u044b, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u0438 \u0432\u044b\u0437\u043e\u0432\u0435 SparkSubmitDockerOperator.\u00a0<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u0434\u0430\u0433\u0430 \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430 \u0432 Airflow \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0442\u0430\u0441\u043a\u0430. \u0423 \u0435\u0435 \u0438\u043d\u0441\u0442\u0430\u043d\u0441\u043e\u0432 \u0432 \u0440\u0430\u0437\u0434\u0435\u043b\u0435 Rendered template \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u043f\u043e\u043b\u0435 rendered_command, \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0435\u0435 \u043f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u043c\u0430\u043d\u0434\u044b, \u0438\u0441\u043f\u043e\u043b\u043d\u044f\u0435\u043c\u043e\u0439 \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435:<\/p>\n<pre><code class=\"bash\"># \u042d\u0442\u043e\u0442 \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439 sh-\u0441\u043a\u0440\u0438\u043f\u0442 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0442\u044c \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 rendered template \u0432 Airflow. \u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 \u0434\u043e\u043a\u0435\u0440 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043f\u043e \u043d\u0435\u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u044e\u0449\u0438\u043c\u0441\u044f \u043f\u0440\u0430\u0432\u0438\u043b\u0430\u043c. \\ export PYTHONPATH=\"..\/:\"; \\ export LMD_ENV_TYPE=\"dev\"; \\ echo \"master.source.jvm.class=org.apache.spark.metrics.source.JvmSource worker.source.jvm.class=org.apache.spark.metrics.source.JvmSource driver.source.jvm.class=org.apache.spark.metrics.source.JvmSource executor.source.jvm.class=org.apache.spark.metrics.source.JvmSource  *.sink.statsd.class=org.apache.spark.metrics.sink.StatsdSink *.sink.statsd.prefix=de_spark.batch *.sink.statsd.period=10 *.sink.statsd.unit=seconds *.sink.statsd.host=thor.dev.dwh.lamoda.tech *.sink.statsd.port=9126\" > \/app\/metrics.conf; \\ spark-submit \\ --master \"yarn\" \\ --queue \"apps\" \\ --deploy-mode \"cluster\" \\ --name \"ip_geo__ip_geo_snapshot\" \\ --driver-cores \"1\" \\ --driver-memory \"2G\" \\ --executor-cores \"1\" \\ --executor-memory \"1G\" \\ --num-executors \"3\" \\ --files \"\/app\/metrics.conf\" \\ --class \"tech.lamoda.dwh.etl.executor.spark_sql.SparkSqlExecutor\" \\ --conf \"spark.yarn.maxAppAttempts=1\" \\ --conf \"spark.driver.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.executor.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.yarn.am.extraJavaOptions=${SPARK_JVM_OPTS}\" \\ --conf \"spark.metrics.conf=metrics.conf\" \\ --conf \"spark.metrics.namespace=ip_geo\" \\ --conf \"spark.sql.broadcastTimeout=1200\" \\ \/data-processing-etl.jar \\ --out-db \"dev_derivatives_db\" \\ --out-table \"ip_geo_snapshot\" \\ --mode \"overwrite\" \\ --partitions-num \"1\" \\ --partitions-cols \"dt\" \\ --sql \"select ip,        country,        region_aoid,        region_name,        region_abbr,        city_aoid,        city_name,        '20240403' as dt from \\\\\\`dev_derivatives_db\\\\\\`.ip_geo\" <\/code><\/pre>\n<p>\u041e\u0431\u0440\u0430\u0442\u0438\u043c \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043f\u0440\u0435\u0434\u0443\u043f\u0440\u0435\u0436\u0434\u0435\u043d\u0438\u0435: \u0434\u0430\u043d\u043d\u0430\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0441\u0430\u0431\u043c\u0438\u0442\u0438\u0442\u0441\u044f \u0432 Doker. \u042d\u0442\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0442\u0430\u043a. \u042d\u0442\u043e\u0442 \u0431\u043b\u043e\u043a \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u0441\u0433\u0435\u043d\u0435\u0440\u0438\u0440\u043e\u0432\u0430\u043d \u0434\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0438 \u0434\u0435\u0431\u0430\u0433\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.\u00a0 \u041f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0435\u043c\u0430\u044f \u0432 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u043d\u0435 \u0441\u0438\u043b\u044c\u043d\u043e \u043e\u0442\u043b\u0438\u0447\u0430\u0435\u0442\u0441\u044f \u043e\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u043d\u043e\u0439: \u0432 \u043d\u0435\u0439 \u0431\u0443\u0434\u0443\u0442 \u0434\u0440\u0443\u0433\u0438\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u044d\u043a\u0440\u0430\u043d\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f, \u0430 env-\u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u0444\u0430\u0439\u043b\u044b \u0431\u0443\u0434\u0443\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u044b \u0447\u0435\u0440\u0435\u0437 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430.<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u0435\u0441\u0442\u0438 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0432\u044b\u0432\u043e\u0434\u0438\u043c\u0443\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u043c\u043e\u0436\u043d\u043e \u0441\u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u043d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440\u0435.<\/p>\n<h3>\u0417\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h3>\n<p>\u041f\u0440\u0438 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u043c\u044b \u0441\u0440\u0430\u0437\u0443 \u0437\u0430\u0434\u0430\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b Spark \u0438 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u044f\u0435\u043c \u0438\u0445 \u0441 \u043f\u043e\u0441\u0442\u0443\u043f\u0438\u0432\u0448\u0438\u043c\u0438 \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0442\u0430\u0441\u043a\u0430\u043c\u0438. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0430\u043c \u043c\u0430\u0441\u0441\u043e\u0432\u043e \u0443\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u043b\u044f \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c <a href=\"https:\/\/spark.apache.org\/docs\/latest\/tuning.html#data-serialization\"><u>KryoSerializer<\/u><\/a> \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u0434\u0430\u0433\u043e\u0432.<\/p>\n<pre><code class=\"python\">class SparkSubmitDockerOperatorV2(LamodaDockerOperator):      default_spark_params = {        \"master\": \"yarn\",        \"queue\": \"{{ var.value.YARN_QUEUE }}\",        \"deploy-mode\": \"cluster\",        \"conf\": {            '\"spark.yarn.maxAppAttempts\"': 1,            '\"spark.hadoop.orc.overwrite.output.file\"': \"true\",            '\"spark.serializer\"': 'org.apache.spark.serializer.KryoSerializer',            '\"spark.kryoserializer.buffer.max\"': '2047m'        },    }<\/code><\/pre>\n<p>\u041d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043c\u043e\u0436\u043d\u043e \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043d\u0435\u0445\u0438\u0442\u0440\u043e\u0433\u043e \u0442\u0440\u044e\u043a\u0430. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043c\u0435\u0442\u043e\u0434 <code>render_template_fields<\/code>\u00a0 \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043a\u043e\u0440\u0442\u0435\u0436 <code>template_fields<\/code> \u043d\u043e\u0432\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 <code>'rendered_command'<\/code>, \u044f\u0432\u043b\u044f\u044e\u0449\u0438\u0435\u0441\u044f \u0438\u043c\u0435\u043d\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0430 \u043a\u043b\u0430\u0441\u0441\u0430 self.rendered_command .<\/p>\n<p>\u0414\u0435\u043c\u043e\u043d\u0441\u0442\u0440\u0430\u0446\u0438\u044f \u0441 \u043a\u0443\u0441\u043e\u0447\u043a\u0430\u043c\u0438 \u043a\u043e\u0434\u0430:<\/p>\n<pre><code class=\"python\">class SparkSubmitDockerOperator(DockerOperator): ... # \u041f\u043e\u043b\u044f \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f jinja \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044f \u043d\u0435\u0442 \u0432 \u043a\u043e\u0440\u0442\u0435\u0436\u0435, \u0442\u043e \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u044b \u043d\u0435 \u0431\u0443\u0434\u0443\u0442 template_fields = (    'rendered_command',     'environment',    'spark_params',    'spark_conf_params',    'program_path',    'job_params',    'job_flags',    'container_name', ) template_fields_renderers: Dict[str, str] = {    'rendered_command': 'bash' } ... # \u041f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 def render_template_fields(self, context: Dict, jinja_env: Optional[jinja2.Environment] = None) -> None:    logger.info(\"\u0417\u0430\u043f\u043e\u043b\u043d\u044f\u0435\u043c \u0448\u0430\u0431\u043b\u043e\u043d\u044b \u0432 \u0442\u0440\u0435\u0431\u0443\u0435\u043c\u044b\u0445 \u043f\u043e\u043b\u044f\u0445, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0439 \u043c\u0435\u0442\u043e\u0434\")    super().render_template_fields(context=context, jinja_env=jinja_env)     logger.info(\"\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c sh \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\")    result_command = self.create_command(        spark_params=self.spark_params,        spark_conf_params=self.spark_conf_params,        program_path=self.program_path,        job_params=self.job_params,        job_flags=self.job_flags,        files=self.spark_files,    )     logger.info(\"\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0432 UI\")    self.rendered_command = self.render_ui_view(result_command, environment=self.environment, files=self.spark_files)     logger.info(\"\u041f\u043e\u0434\u0433\u043e\u0442\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0432 Docker\")    self.command = self.prepare_docker_command(result_command) <\/code><\/pre>\n<p>\u0412 \u0431\u043b\u043e\u043a\u0435 \u043a\u043e\u0434\u0430 \u0432\u0438\u0434\u043d\u043e, \u0447\u0442\u043e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043a\u043e\u043c\u0430\u043d\u0434\u0430, \u0432\u044b\u0432\u043e\u0434\u0438\u043c\u0430\u044f \u043d\u0430 UI, \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u2014 \u043a\u043e\u043c\u0430\u043d\u0434\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430. \u041f\u0440\u0438 \u0441\u0442\u0430\u0440\u0442\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 DockerOperator \u0432\u043e\u0437\u044c\u043c\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u0443, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043b\u0435\u0436\u0438\u0442 \u0432 \u043f\u043e\u043b\u0435 self.command, \u0432 \u0442\u043e \u0432\u0440\u0435\u043c\u044f \u043a\u0430\u043a rendered_command \u043e\u0442\u043f\u0440\u0430\u0432\u0438\u0442\u0441\u044f \u043d\u0430 UI.<\/p>\n<h3>\u0414\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u043e\u0432<\/h3>\n<p>\u041c\u044b \u0445\u043e\u0442\u0435\u043b\u0438 \u0438\u043c\u0435\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b\u044b \u0438\u043b\u0438 \u0438\u0445 \u043a\u043e\u043d\u0442\u0435\u043d\u0442 \u0432 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u0445 \u0442\u0430\u0441\u043a\u0438 \u0432 \u043f\u043e\u043b\u0435 spark-files. \u041f\u0440\u043e\u0431\u043b\u0435\u043c\u0430 \u0437\u0430\u043a\u043b\u044e\u0447\u0430\u043b\u0430\u0441\u044c \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 \u0444\u0430\u0439\u043b\u0430\u0445 \u0442\u043e\u0436\u0435 \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c Jinja-\u0448\u0430\u0431\u043b\u043e\u043d\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c.\u00a0<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0445\u043e\u0442\u0435\u043b\u0438, \u0447\u0442\u043e\u0431\u044b \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435 Rendered template \u044d\u0442\u0438 \u0444\u0430\u0439\u043b\u044b \u0432\u044b\u0432\u043e\u0434\u0438\u043b\u0438\u0441\u044c \u0432 \u0438\u0442\u043e\u0433\u043e\u0432\u043e\u043c \u0432\u0438\u0434\u0435, \u0432 \u0442\u043e\u043c, \u0432 \u043a\u0430\u043a\u043e\u043c \u043e\u043d\u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u044f\u0442\u0441\u044f \u0432 Docker. \u0427\u0442\u043e\u0431\u044b \u0444\u0430\u0439\u043b\u044b \u043f\u0440\u043e\u0448\u043b\u0438 \u0447\u0435\u0440\u0435\u0437 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0438 \u0432\u044b\u0432\u0435\u043b\u0438\u0441\u044c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e, \u0447\u0442\u043e\u0431\u044b \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043d\u0438\u0445 \u043f\u043e\u044f\u0432\u0438\u043b\u0430\u0441\u044c \u0432 \u043f\u043e\u043b\u0435 <code>template_fields<\/code> . \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0432 init-\u043c\u0435\u0442\u043e\u0434\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u0441 \u0438\u043c\u0435\u043d\u0430\u043c\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438 \u0438\u043c\u0435\u043d\u0430\u043c \u0444\u0430\u0439\u043b\u043e\u0432, \u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u043c\u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u043c\u0443 \u0444\u0430\u0439\u043b\u043e\u0432. \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0445 \u0438\u043c\u0435\u043d\u0430 \u0432 template_fields \u0438 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0432 <code>template_fields_renderers<\/code> (\u043e\u043d\u043e \u043d\u0443\u0436\u043d\u043e \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0432\u0435\u0442\u043a\u0438 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441\u0430):<\/p>\n<pre><code class=\"python\">class SparkSubmitDockerOperatorV2(LamodaDockerOperator): ...      template_fields = (         'rendered_command',         'environment',         'spark_params',         'spark_conf_params',         'program_path',         'job_params',         'job_flags',         'container_name',     )      template_fields_renderers: Dict[str, str] = {         'rendered_command': 'bash'     }      def __init__(             self,             image,             ...     ):     ...         for file_name, content in spark_files.items():             logger.info(f\"\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0444\u0430\u0439\u043b\u044b \u0432 template {file_name}\")             setattr(self, file_name, content)             # \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u044b \u0441 \u043a\u043e\u0442\u0435\u043d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u043e\u0432 \u0438 \u0438\u0445 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f \u0432 Renderred UI             file_extension = get_file_extension(file_name)             self.template_fields += (file_name,)             self.template_fields_renderers[file_name] = file_extension <\/code><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a \u0441\u0430\u043c\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0432 \u043c\u0435\u0442\u043e\u0434\u0435-\u0440\u043e\u0434\u0438\u0442\u0435\u043b\u0435 DockerOperator.run_image. \u0427\u0442\u043e\u0431\u044b \u0444\u0430\u0439\u043b\u044b \u043f\u043e\u043f\u0430\u043b\u0438 \u0432 \u043e\u0431\u0440\u0430\u0437, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0435\u0433\u043e \u0432 mount. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u0435\u043c \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e, \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c \u0432 \u043d\u0435\u0439 \u0444\u0430\u0439\u043b \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0435\u0433\u043e \u043a \u0430\u0442\u0440\u0438\u0431\u0443\u0442\u0443 mounts:<\/p>\n<pre><code class=\"python\">def _run_image(self) -> Optional[str]:    with TemporaryDirectory(prefix='spark_files', dir=self.host_tmp_dir) as spark_files_temp_dir:        for spark_file_path in self.spark_files.keys():            rendered_content = getattr(self, spark_file_path)            filename = Path(spark_file_path).name            temp_file_path = Path(spark_files_temp_dir, filename)            with open(temp_file_path, \"w\") as spark_file:                spark_file.write(rendered_content)            self.mounts += [Mount(target=spark_file_path, source=str(temp_file_path), type=\"bind\")]          return super()._run_image()<\/code><\/pre>\n<p>\u0414\u0430\u043b\u044c\u0448\u0435 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 DockerOperator \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u0431\u0440\u0430\u0437, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0432 \u043d\u0435\u043c \u043c\u0435\u0442\u043e\u0434 _run_image. \u041e\u043d \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u0445\u0432\u0430\u0442\u044b\u0432\u0430\u0435\u0442 \u0442\u0430\u043a\u0438\u0435 \u043f\u043e\u043b\u044f, \u043a\u0430\u043a self.command, self.environment, \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0435 \u0434\u043b\u044f mount \u0444\u0430\u0439\u043b\u044b \u0438\u0437 \u043f\u043e\u043b\u0435\u0439 \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440 \u0438 \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u0442 \u0435\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435.\u00a0<\/p>\n<h2>\u041b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439<\/h2>\n<p>\u041d\u0435 \u0432\u0441\u0435\u043c \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430\u043c \u0443\u0434\u043e\u0431\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 dev-\u0441\u0442\u0435\u043d\u0434\u0430\u0445, \u0432\u0435\u0434\u044c \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043a\u043e\u043c\u043c\u0438\u0442\u0430 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0436\u0438\u0434\u0430\u0442\u044c\u0441\u044f, \u043f\u043e\u043a\u0430 \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0442\u0435\u0441\u0442\u044b, \u043f\u0440\u043e\u0439\u0434\u0443\u0442 \u0431\u0438\u043b\u0434\u044b \u0438 \u0434\u0435\u043f\u043b\u043e\u0439. \u0414\u043b\u044f \u043d\u0438\u0445 \u043f\u0440\u043e\u0449\u0435 \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437 \u043d\u0430 \u0441\u0432\u043e\u0439 \u043a\u043e\u043c\u043f\u044c\u044e\u0442\u0435\u0440 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c docker run. \u041f\u0440\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b SparkSubmitDockerOperator \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u043c, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0437\u0430\u0434\u0430\u0432\u0430\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 HOCON-\u043a\u043e\u043d\u0444\u0438\u0433\u043e\u0432 \u0431\u0435\u0437 \u0432\u0441\u043f\u043e\u043c\u043e\u0433\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f .sh \u0444\u0430\u0439\u043b\u0430\u043c\u0438 \u0438\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u0443 \u0442\u0435\u043a\u0441\u0442\u043e\u043c, \u0447\u0442\u043e \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u043a \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0441\u043e\u0432\u0435\u0440\u0448\u0430\u0442\u044c \u0434\u0432\u043e\u0439\u043d\u0443\u044e \u0440\u0430\u0431\u043e\u0442\u0443. \u041f\u0435\u0440\u0432\u044b\u0439 \u0440\u0430\u0437 \u043f\u0438\u0448\u0435\u043c \u043a\u043e\u0434 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 spark-submit \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 .sh \u0444\u0430\u0439\u043b\u0430 \u0438\u043b\u0438 \u0442\u0435\u043a\u0441\u0442\u0430, \u0430 \u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0440\u0430\u0437 \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u043e\u0435 \u043d\u0430 \u0440\u0435\u043b\u044c\u0441\u044b \u0434\u0430\u0433\u043e\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438.\u00a0<\/p>\n<p>\u0427\u0442\u043e\u0431\u044b \u0440\u0435\u0448\u0438\u0442\u044c \u044d\u0442\u0443 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0438 \u0432\u0435\u0437\u0434\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c HOCON-\u043a\u043e\u043d\u0444\u0438\u0433\u0438, \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u0438 Python-\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 spark_submit_runner. \u041e\u043d\u0430 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 SparkSubmitDockerOperator.\u00a0<\/p>\n<p>\u041f\u043e\u043c\u0438\u043c\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430 \u2014 <code>airflow_builtins.conf<\/code> \u0438 <code>task_conf.conf<\/code> (\u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0435\u043c\u0443 \u0431\u043e\u043b\u0435\u0435 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0438\u043c\u044f). \u041f\u0435\u0440\u0432\u044b\u0439 \u2014 \u044d\u0442\u043e \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0437\u0430\u0433\u043b\u0443\u0448\u043a\u0430, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u0430\u044f \u0434\u043b\u044f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445, \u043c\u0430\u043a\u0440\u043e\u0441\u043e\u0432 \u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d\u043e\u0432 Airflow \u0432 Jinja-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043f\u0440\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435. \u0412\u0442\u043e\u0440\u043e\u0439 \u2014 \u044d\u0442\u043e \u0444\u0430\u0439\u043b \u0441 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c \u0442\u0430\u0441\u043a\u0438, \u043a\u0430\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0432 Airflow.\u00a0<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f airflow_builtins.conf:<\/p>\n<pre><code class=\"python\">airflow-macros {   ds = \"2023-03-22\" }   airflow-vars {   HIVE_DB_DERIVATIVES = \"derivatives_db\" }   airflow-connections {   connection_id {     conn_type = \"conn_type\"     host = \"host\"     login = \"login\"     password = \"password\"     schema = \"schema\"     port = \"port\"     extra_dejson {       extra__jdbc__drv_clsname = \"oracle.jdbc.driver.OracleDriver\"       extra_connection_type = \"service_name\"     }   } }<\/code><\/pre>\n<p>\u0422\u0430\u043a\u0436\u0435 \u0432\u043e \u0432\u0440\u0435\u043c\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043b\u0438\u0431\u044b \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u044c \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f <a href=\"https:\/\/python-packaging.readthedocs.io\/en\/latest\/command-line-scripts.html#the-console-scripts-entry-point\"><u>\u043a\u043e\u043c\u0430\u043d\u0434\u0430<\/u><\/a> <code>spark-submit-runner<\/code>. \u041e\u043d\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u0432 Docker-\u043e\u0431\u0440\u0430\u0437\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0442\u0430\u043a:\u00a0<\/p>\n<p><code>spark-submit-runner -i image_name -c local_runner_confs\/task_conf.conf<\/code><\/p>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0435 \u0441\u0434\u0435\u043b\u0430\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u043f\u043e\u0441\u043b\u0435 \u043d\u0430\u0436\u0430\u0442\u0438\u044f \u043d\u0430 Enter \u0432\u044b \u0443\u0432\u0438\u0434\u0438\u0442\u0435 \u0442\u0435 \u0436\u0435 \u043b\u043e\u0433\u0438, \u0447\u0442\u043e \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u044e\u0442\u0441\u044f \u0432\u043e \u0432\u043a\u043b\u0430\u0434\u043a\u0435 logs \u0432 Airflow, \u043d\u043e \u0443 \u0441\u0435\u0431\u044f \u0432 \u043a\u043e\u043d\u0441\u043e\u043b\u0438.<\/p>\n<p>\u0427\u0442\u043e \u043d\u0430\u043c \u044d\u0442\u043e \u0434\u0430\u043b\u043e<\/p>\n<p>\u0422\u0430\u043a\u043e\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u043c\u0435\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0437\u0440\u0430\u0447\u043d\u043e\u0441\u0442\u044c \u0432 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0438 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438. \u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0434\u0435\u043b\u0430\u044e\u0442 Pull Request \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c\u0438 \u0434\u0430\u0433\u043e\u0432, \u043c\u044b \u043f\u043e\u043d\u0438\u043c\u0430\u0435\u043c, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 \u043e\u043d\u0438 \u0431\u0435\u0440\u0443\u0442 \u0438 \u0441 \u043a\u0430\u043a\u0438\u043c\u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438.\u00a0 <\/p>\n<\/li>\n<li>\n<p>\u0412\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043b\u0435\u0433\u043a\u043e \u0438 \u0431\u044b\u0441\u0442\u0440\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0438 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435. \u041c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0443\u043b\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u0432\u0441\u0435\u0445 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0438\u0437 \u043a\u043e\u043d\u0444\u0438\u0433\u0430. \u042d\u0442\u043e \u043f\u043e\u0437\u0432\u043e\u043b\u0438\u043b\u043e \u0432\u043a\u043b\u044e\u0447\u0438\u0442\u044c KryoSerializer \u0432\u043e \u0432\u0441\u0435 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0431\u0443\u043a\u0432\u0430\u043b\u044c\u043d\u043e \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0442\u0440\u043e\u043a \u043a\u043e\u0434\u0430. \u0422\u0430\u043a\u0436\u0435 \u043c\u044b \u0441\u043c\u043e\u0433\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u043f\u043e\u0441\u0442\u0435\u043f\u0435\u043d\u043d\u043e\u0439 \u0440\u0430\u0441\u043a\u0430\u0442\u043a\u0438 \u0434\u043b\u044f \u043c\u0430\u0441\u0441\u043e\u0432\u043e\u0433\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430. <\/p>\n<\/li>\n<li>\n<p>\u0413\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044f \u0438\u043c\u0435\u043d\u0438 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 \u0431\u0443\u0434\u0435\u0442 <a href=\"http:\/\/spark.name\">spark.name<\/a> \u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 \u043c\u044b. \u0414\u043e\u0431\u0430\u0432\u0438\u043b\u0438 \u043f\u0440\u043e\u0431\u0440\u043e\u0441\u043a\u0443 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 name \u0438\u0437 Airflow \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0432\u0438\u0434\u0435 &lt;dag_name>__&lt;task_name> \u2014 \u0438 \u043d\u0430\u0448\u0430 Grafana \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442, \u043a\u0430\u043a\u043e\u0439 \u0434\u0430\u0433 \u0432 Airflow \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u0442. \u0420\u0430\u043d\u044c\u0448\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0438\u0441\u043a\u0430\u0442\u044c \u044d\u0442\u043e \u0440\u0443\u043a\u0430\u043c\u0438 \u043f\u043e \u043a\u043e\u0434\u0443.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/01f\/aef\/ca2\/01faefca2658efc5019770a8bc06bb5c.png\" width=\"1600\" height=\"875\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/01f\/aef\/ca2\/01faefca2658efc5019770a8bc06bb5c.png\"\/><\/figure>\n<\/li>\n<li>\n<p>\u0423\u043f\u0440\u043e\u0449\u0435\u043d\u0438\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0438\u0448\u0435\u0442 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0442\u0430\u0441\u043a\u0438 \u0432 \u0442\u043e\u043c \u0436\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u0435, \u0432 \u043a\u0430\u043a\u043e\u043c \u043e\u043d\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0430 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u0441 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f\u043c\u0438. \u042d\u0442\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0432\u044b\u043a\u0430\u0442\u043a\u0438 \u043d\u043e\u0432\u044b\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u0432 \u043f\u0440\u043e\u0434 (\u0422\u0422\u041c). \u0412\u044b\u043a\u0430\u0442\u043a\u0430 \u0441\u0442\u0430\u043b\u0430 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0442\u044c \u0438\u0437 \u0441\u0435\u0431\u044f ctrl+c ctrl+v \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0439.\u00a0<\/p>\n<\/li>\n<\/ul>\n<p>\u041c\u044b \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u044b \u0441\u0432\u043e\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0448\u0430\u0433\u0438 \u0432 \u043d\u0430\u0448\u0438\u0445 \u043f\u043b\u0430\u043d\u0430\u0445 \u2014 \u043e\u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440 \u0438 \u043a\u043e\u0434 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 \u043d\u0430 GitHub \u0432 \u0432\u0438\u0434\u0435 opensource-\u043f\u0440\u043e\u0432\u0430\u0439\u0434\u0435\u0440\u0430 \u0434\u043b\u044f Airflow \u0438 \u0432\u044b\u043b\u043e\u0436\u0438\u0442\u044c \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u0432 PyPi, \u043a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u043e\u0433\u043b\u0430\u0441\u0443\u0435\u043c \u0432\u0441\u0435 \u0432\u043d\u0443\u0442\u0440\u0438.<\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/810705\/\"> https:\/\/habr.com\/ru\/articles\/810705\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><\/figure>\n<p>Airflow \u0432 Lamoda Tech \u0438\u0433\u0440\u0430\u0435\u0442 \u0440\u043e\u043b\u044c \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0430\u0442\u043e\u0440\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0432 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0436\u0435\u0434\u043d\u0435\u0432\u043d\u043e \u0441 \u0435\u0433\u043e \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c 1 800+ \u0442\u0430\u0441\u043e\u043a \u043d\u0430 \u043f\u0440\u043e\u0434\u0435, \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u043f\u043e\u043b\u043e\u0432\u0438\u043d\u0430 \u0438\u0437 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u043c\u0438.<\/p>\n<p>\u0412\u0441\u0435 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0441\u0430\u0431\u043c\u0438\u0442\u044f\u0442\u0441\u044f \u0438\u0437 Docker-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u043e\u0432. \u0418 \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u0430\u043b\u043a\u0438\u0432\u0430\u0435\u043c\u0441\u044f \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439: \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0440\u0435\u0448\u0435\u043d\u0438\u0439 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044e\u0449\u0438\u0445 \u043b\u0435\u0433\u043a\u043e \u043f\u0440\u0430\u0432\u0438\u0442\u044c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0438 \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u043b\u044f\u0435\u043c\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432.<\/p>\n<p>\u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u0410\u043d\u0434\u0440\u0435\u0439 \u0411\u0443\u043b\u0433\u0430\u043a\u043e\u0432, \u044f \u043b\u0438\u0434 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 Big Data \u0432 Lamoda Tech. \u0412\u043c\u0435\u0441\u0442\u0435 \u0441 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u043c \u0418\u0432\u0430\u043d\u043e\u043c \u0412\u0430\u0441\u0435\u043d\u043a\u043e\u0432\u044b\u043c <a class=\"mention\" href=\"\/users\/vasenkovid\">@vasenkovid<\/a> \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043c\u044b \u043f\u043e\u0434\u0435\u043b\u0438\u043c\u0441\u044f \u0438\u0441\u0442\u043e\u0440\u0438\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Airflow-\u043e\u043f\u0435\u0440\u0430\u0442\u043e\u0440\u0430 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439.<\/p>\n<h2>\u041a\u0430\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u044f\u0442 \u043d\u0430\u0448\u0438 Airflow \u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u044b<\/h2>\n<p>\u041f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u0440\u0430\u0437\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0445\u043e\u0447\u0443 \u043d\u0435\u043c\u043d\u043e\u0433\u043e \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c \u043f\u0440\u043e \u043d\u0430\u0448 \u043f\u043e\u0434\u0445\u043e\u0434 \u043a \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u0432 Airflow. \u042d\u0442\u043e \u0434\u0430\u0441\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0441\u0432\u0435\u0440\u0445\u0443.\u00a0<\/p>\n<p>\u041f\u043e\u0434\u0440\u043e\u0431\u043d\u043e \u043e \u0442\u043e\u043c, \u043a\u0430\u043a \u043c\u044b \u043e\u0440\u043a\u0435\u0441\u0442\u0440\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u044b \u0443\u0436\u0435 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0438 \u0432 <a href=\"https:\/\/habr.com\/ru\/companies\/lamoda\/articles\/518620\/\"><u>\u0441\u0442\u0430\u0442\u044c\u0435<\/u><\/a>. \u0415\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0440\u043e\u0448\u043e \u0437\u043d\u0430\u043a\u043e\u043c\u044b \u0441 \u044d\u0442\u043e\u0439 \u0442\u0435\u043c\u043e\u0439, \u0431\u043b\u043e\u043a \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c.<\/p>\n<p>\u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u043a\u043e\u0440\u043e\u0442\u043a\u043e \u043f\u0440\u043e \u043d\u0430\u0448 Airflow. \u0412 PROD-\u043a\u043e\u043d\u0442\u0443\u0440\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 370+ \u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0445 \u0434\u0430\u0433\u043e\u0432 (DAG \u2014 Directed Acyclic Graph), \u0430 \u0432 DEV-\u043a\u043e\u043d\u0442\u0443\u0440\u0435 \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 Big Data, \u0434\u0430\u0442\u0430-\u0441\u0430\u0439\u0435\u043d\u0442\u0438\u0441\u0442\u043e\u0432 \u0438 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u043e\u0432 \u043d\u0430 \u0441\u0432\u043e\u0438\u0445 \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0440\u0430\u0437\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u044e\u0442 \u0438 \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u044e\u0442 \u043d\u0430\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0435\u0440\u0435\u0434 \u0432\u044b\u043a\u0430\u0442\u043e\u043c \u043d\u0430 PROD.<\/p>\n<figure class=\"full-width\"><\/figure>\n<p>\u041f\u043e\u0434 \u043a\u0430\u0436\u0434\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u0441\u043e\u0437\u0434\u0430\u043d\u0430 \u0441\u0432\u043e\u044f \u0432\u0435\u0442\u043a\u0430 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0427\u0442\u043e\u0431\u044b \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u043f\u0440\u0438 \u0432\u043d\u0435\u0441\u0435\u043d\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0432 master-\u0432\u0435\u0442\u043a\u0443, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0443\u044e \u0437\u0430 PROD, \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 merge \u0432 \u0432\u0435\u0442\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 DEV-\u043a\u043e\u043d\u0442\u0443\u0440\u0435.<\/p>\n<p>\u0422\u0435\u0441\u0442\u043e\u0432\u044b\u0439 \u0441\u0442\u0435\u043d\u0434 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439 Airflow, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043d\u044f\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435 \u043e \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u0435\u0437\u0434\u0430. \u041d\u0430 \u043c\u043e\u043c\u0435\u043d\u0442 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0441\u0442\u0430\u0442\u044c\u0438 \u043d\u0430 \u0432\u0441\u0435\u0445 \u0441\u0442\u0435\u043d\u0434\u0430\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432\u0435\u0440\u0441\u0438\u044f Airflow 2.7.3 \u043d\u0430 Celery Executor.<\/p>\n<p>\u0414\u043b\u044f \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u043e\u0432 \u043c\u044b \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0434\u0430\u0433\u0438 \u043d\u0435 \u0432 \u043a\u043e\u0434\u0435, \u0430 \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0444\u0430\u0439\u043b\u0430\u0445.\u00a0<\/p>\n<p>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0437\u0430\u0434\u0430\u0435\u043c \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <a href=\"https:\/\/github.com\/lightbend\/config\/blob\/master\/HOCON.md\"><u>HOCON<\/u><\/a> (Human-Optimized Config Object Notation) \u2014 \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0439 \u0434\u043b\u044f \u0447\u0442\u0435\u043d\u0438\u044f \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0447\u0435\u043b\u043e\u0432\u0435\u043a\u043e\u043c \u0432\u0435\u0440\u0441\u0438\u0438 JSON. \u0421\u0440\u0435\u0434\u0438 <a href=\"https:\/\/github.com\/lightbend\/config\/blob\/master\/HOCON.md#goals--background\"><u>\u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0435\u0439 \u0444\u043e\u0440\u043c\u0430\u0442\u0430 HOCON<\/u><\/a> \u0434\u043b\u044f \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432:<\/p>\n<ul>\n<li>\n<p>\u043c\u0438\u043d\u0438\u043c\u0430\u043b\u0438\u0441\u0442\u0438\u0447\u043d\u044b\u0439 \u0441\u0438\u043d\u0442\u0430\u043a\u0441\u0438\u0441,<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0438\u043c\u043f\u043e\u0440\u0442\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 HOCON-\u0444\u0430\u0439\u043b\u043e\u0432,\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0441\u044b\u043b\u0430\u0442\u044c\u0441\u044f \u043d\u0430 \u0434\u0440\u0443\u0433\u0438\u0435 \u0447\u0430\u0441\u0442\u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0443\u0440\u043e\u0432\u043d\u044f \u043f\u0430\u0439\u043f\u043b\u0430\u0439\u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u043a\u043e\u043d\u0444\u0438\u0433\u0430. \u0412 \u043d\u0438\u0445 \u0432\u0445\u043e\u0434\u044f\u0442 <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow\/stable\/_api\/airflow\/models\/dag\/index.html#airflow.models.dag.DAG\"><u>\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u0430\u0433\u0430<\/u><\/a>, \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u0432\u043b\u0430\u0434\u0435\u043b\u044c\u0446\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u0430\u0441\u0441\u044b\u043b\u043a\u0438 \u043f\u043e \u043f\u043e\u0447\u0442\u0435 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0439 \u043e \u0435\u0433\u043e \u043f\u0430\u0434\u0435\u043d\u0438\u0438. \u0422\u0430\u043a\u0436\u0435 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f \u043e \u043f\u0430\u0434\u0435\u043d\u0438\u0438 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u0442 \u0434\u0435\u0436\u0443\u0440\u043d\u043e\u043c\u0443 \u0434\u0430\u0442\u0430-\u0438\u043d\u0436\u0435\u043d\u0435\u0440\u0443, \u0438 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u044b \u043a\u043e\u0440\u043f\u043e\u0440\u0430\u0442\u0438\u0432\u043d\u043e\u0433\u043e \u043c\u0435\u0441\u0441\u0435\u043d\u0434\u0436\u0435\u0440\u0430.<\/p>\n<pre><code class=\"python\">include \"..\/..\/generics\/emails.conf\"  dags {   main_pa_metrics {     owner = \"RND-PA\"     name = \"main_pa_metrics\"     start_date = \"20220327\"     emails = ${PRODUCT_ANALYSTS_TEAM}     schedule_interval = \"30 9 * * *\"     catchup = true     notify_on_failure = {       title = \"{dag_id} FAILED\",       message = \"\u0423\u043f\u0430\u043b \u0440\u0430\u0441\u0447\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0438 \u0432 \u043a\u043e\u043d\u0444\u043b\u044e\u0435\u043d\u0441. \u0412\u0430\u0436\u043d\u043e \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0434\u043e 12 \u0434\u043d\u044f.\",       to = {         pachca = [{           connection= \"pachca_alerts_etl\"         }, {           connection= \"pachca_alerts_pa_automation\"         }]       }     }    description = \"\u0414\u0430\u0433 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b pa_db.main_pa_metrics \u0441 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a\"   tags = [       \"critical\", \"pa\"     ] <\/code><\/pre>\n<p>\u0412 \u044d\u0442\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043e\u043f\u0438\u0441\u0430\u043d\u044b \u0434\u0432\u0430 \u0448\u0430\u0433\u0430: \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u044b \u0432 Oracle \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0432 Trino. <\/p>\n<pre><code class=\"python\">    tasks {       await_visitor_activity_ready {         type = \"oracle_sensor\"         sensor_type = \"job_code\"         conn_id = \"dwh\"         job_code = \"ORA_VISITOR_ACTIVITY\"         dt = \"{{ ds_nodash }}\"       }       load_trino {         type = \"trino\"         sql_params {           hive_schema = \"{{ var.value.HIVE_DB_PA }}\"           start_dt = \"{{ ds }}\"           end_dt = \"{{ next_ds }}\"         }         sql_file = \"trino\/main_pa_metrics.sql\"       }       task_order = [         \"await_visitor_activity_ready\",         \"load_trino\"       ]     }<\/code><\/pre>\n<p>\u0414\u043b\u044f \u043f\u043e\u0434\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u043d\u0443\u0436\u043d\u044b\u0445 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0434\u0430\u0442\u044b \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0438 \u0441\u0442\u0435\u043d\u0434\u0430 Airflow \u0432 \u043a\u043e\u043d\u0444\u0438\u0433\u0435 \u0447\u0435\u0440\u0435\u0437 Jinja-\u0448\u0430\u0431\u043b\u043e\u043d\u044b \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow\/stable\/templates-ref.html\"><u>\u043c\u0430\u043a\u0440\u043e\u0441\u044b, \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0438 \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u0435\u043d\u044b<\/u><\/a>:<\/p>\n<ul>\n<li>\n<p>\u0432 \u043f\u0435\u0440\u0432\u043e\u0439 \u0442\u0430\u0441\u043a\u0435 \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u043a\u043e\u043d\u043d\u0435\u043a\u0448\u043d \u0434\u043b\u044f Oracle, \u0438\u043c\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0438 \u0434\u0430\u0442\u0443, \u0437\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043e\u043d\u0430 \u0434\u043e\u043b\u0436\u043d\u0430 \u043e\u0442\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c;\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0432\u043e \u0432\u0442\u043e\u0440\u043e\u0439 \u0442\u0430\u0441\u043a\u0435 \u2014 \u0443\u043a\u0430\u0437\u0430\u0442\u044c, \u0433\u0434\u0435 \u043b\u0435\u0436\u0438\u0442 \u043a\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0432 \u0437\u0430\u043f\u0440\u043e\u0441.\u00a0\u00a0<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0442\u0430\u0441\u043e\u043a \u0437\u0430\u0434\u0430\u0435\u0442\u0441\u044f \u0432 \u0432\u0438\u0434\u0435 \u0441\u043f\u0438\u0441\u043a\u0430. \u041c\u043e\u0436\u043d\u043e \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u0442\u044c \u0438\u0445 \u0432 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u043f\u0438\u0441\u043e\u043a \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0433\u043e \u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0437\u0430\u0434\u0430\u0447.<\/p>\n<details class=\"spoiler\">\n<summary>\u041f\u0440\u0438\u043c\u0435\u0440 \u043a\u043e\u0434\u0430 \u0434\u0430\u0433\u0430 \u0446\u0435\u043b\u0438\u043a\u043e\u043c<\/summary>\n<div class=\"spoiler__content\">\n<pre><code class=\"python\">include \"..\/..\/generics\/emails.conf\"  dags {   main_pa_metrics {     owner = \"RND-PA\"     name = \"main_pa_metrics\"     start_date = \"20220327\"     emails = ${PRODUCT_ANALYSTS_TEAM}     schedule_interval = \"30 9 * * *\"     catchup = true     notify_on_failure = {       title = \"{dag_id} FAILED\",       message = \"\u0423\u043f\u0430\u043b \u0440\u0430\u0441\u0447\u0435\u0442 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a. \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c \u0441\u043c\u043e\u0442\u0440\u0438 \u0432 \u043a\u043e\u043d\u0444\u043b\u044e\u0435\u043d\u0441. \u0412\u0430\u0436\u043d\u043e \u0435\u0433\u043e \u043f\u0435\u0440\u0435\u043f\u043e\u0434\u043d\u044f\u0442\u044c \u0434\u043e 12 \u0434\u043d\u044f.\",       to = {         pachca = [{           connection= \"pachca_alerts_etl\"         }, {           connection= \"pachca_alerts_pa_automation\"         }]       }     }     description = \"\u0414\u0430\u0433 \u0434\u043b\u044f \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b pa_db.main_pa_metrics \u0441 \u0440\u0430\u0441\u0447\u0435\u0442\u043e\u043c \u0433\u043b\u0430\u0432\u043d\u044b\u0445 \u043f\u0440\u043e\u0434\u0443\u043a\u0442\u043e\u0432\u044b\u0445 \u043c\u0435\u0442\u0440\u0438\u043a\"     tags = [       \"critical\", \"pa\"     ]     tasks {       await_visitor_activity_ready {         type = \"oracle_sensor\"         sensor_type = \"job_code\"         conn_id = \"dwh\"         job_code = \"ORA_VISITOR_ACTIVITY\"         dt = \"{{ ds_nodash }}\"       }       load_trino {         type = \"trino\"         sql_params {           hive_schema = \"{{ var.value.HIVE_DB_PA }}\"           start_dt = \"{{ ds }}\"           end_dt = \"{{ next_ds }}\"         }         sql_file = \"trino\/main_pa_metrics.sql\"       }       task_order = [         \"await_visitor_activity_ready\",         \"load_trino\"       ]     }   } } <\/code><\/pre>\n<\/p>\n<\/div>\n<\/details>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0434\u0430\u0433, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0438\u0437 \u0434\u0432\u0443\u0445 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u0442\u0430\u0441\u043e\u043a.<\/p>\n<figure class=\"full-width\"><\/figure>\n<h2>\u041a\u0430\u043a \u043c\u044b \u0432\u0430\u0440\u0438\u043c Spark<\/h2>\n<p>\u0412 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u0435 \u0434\u0430\u043d\u043d\u044b\u0445 Lamoda Tech \u043c\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u043c \u00ab\u0434\u043e\u043a\u0435\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0439\u00bb Spark. Docker \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432 \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435, \u0438 \u0443\u043f\u0430\u043a\u043e\u0432\u0430\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u0432\u0441\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 \u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0435\u0434\u0438\u043d\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0440\u0435\u0434\u044a\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043a \u043c\u0430\u0448\u0438\u043d\u0435, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442\u0441\u044f Spark, \u2014 \u044d\u0442\u043e \u043d\u0430\u043b\u0438\u0447\u0438\u0435 \u043d\u0430 \u043d\u0435\u0439 Docker.<\/p>\n<p>\u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark. \u041d\u0430 \u0435\u0433\u043e \u043e\u0441\u043d\u043e\u0432\u0435 \u043c\u044b \u0441\u0442\u0440\u043e\u0438\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043e\u0431\u0440\u0430\u0437\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0435. \u0412 \u0431\u0430\u0437\u043e\u0432\u043e\u043c \u043e\u0431\u0440\u0430\u0437\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u0441\u044f \u0441\u043e\u0431\u0440\u0430\u043d\u043d\u044b\u0439 Spark, \u043a\u043e\u043d\u0444\u0438\u0433\u0438 Hadoop \u0438 \u043e\u0431\u044a\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f.\u00a0<\/p>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430:<\/p>\n<pre><code class=\"lua\">FROM docker-registry.lamoda.ru\/centos:7.9.2009   # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Python \u0438 OpenJDK RUN yum install -y curl python3-3.6.8 java-1.8.0-openjdk &amp;&amp; \\   yum clean all &amp;&amp; \\   rm -rf \/var\/cache\/yum   # \u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u043d\u0438\u043a\u0438 Spark COPY build\/spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz \".\/\" RUN tar -xzf spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz &amp;&amp; \\   mv spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION} $SPARK_HOME &amp;&amp; \\   rm spark-${SPARK_VERSION}-bin-hadoop${HADOOP_VERSION}.tgz ENV PATH $SPARK_HOME\/bin:$PATH   # \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0438 COPY configs\/datalake\/hadoop\/conf \/opt\/hadoop\/conf COPY [\"configs\/spark-defaults.conf\", \"configs\/spark-env.sh\", \"configs\/log4j.properties\", \"$SPARK_HOME\/conf\/\"]   # \u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u044f ENV HADOOP_CONF_DIR \/opt\/hadoop\/conf ENV YARN_CONF_DIR \/opt\/hadoop\/conf ENV HIVE_CONF_DIR \/opt\/hadoop\/conf   # \u0417\u0430\u0434\u0430\u0435\u043c \u0434\u0435\u0444\u043e\u043b\u0442\u043d\u044b\u0435 jvm options \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\u0445. \u041c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b ENV SPARK_JVM_OPTS \"-Dhdp.version=current -XX:+UseNUMA -XX:+UseG1GC\"   ENTRYPOINT [\"\/bin\/bash\"]<\/code><\/pre>\n<p>\u041a\u0430\u043a \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u044b\u0439 \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0437:<\/p>\n<ul>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0434 \u043d\u0430\u043f\u0438\u0441\u0430\u043d \u043d\u0430 Scala\/Java, \u0442\u043e \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0432 \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u043e\u0431\u0440\u0430\u0437 JAR \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u0415\u0441\u043b\u0438 \u043d\u0430 Python, \u0442\u043e \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0432\u043c\u0435\u0441\u0442\u0435 \u0441\u043e \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u043c\u0438 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u043c\u0438 \u0434\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f PySpark-\u043a\u043e\u0434\u0430.\u00a0<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 Scala\/Java:<\/p>\n<pre><code class=\"lua\"># \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 (\u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435) FROM docker-registry.lamoda.ru\/base\/lmd-spark:3.3.1-51   # \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0432 \u043e\u0431\u0440\u0430\u0437 jar \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c COPY target\/scala-2.12\/aerospike-loader.jar \/aerospike-loader.jar   ENTRYPOINT [\"\/bin\/bash\"]<\/code><\/pre>\n<p>\u041f\u0440\u0438\u043c\u0435\u0440 Dockerfile \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0441 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c \u043d\u0430 Python:<\/p>\n<pre><code class=\"lua\"># \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0441 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043e\u0431\u0440\u0430\u0437\u0430 (\u0441\u043e\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0432\u044b\u0448\u0435) FROM docker-registry.lamoda.ru\/base\/lmd-spark:3.3.1-51   COPY . \/tmp\/build\/   # \u043f\u0430\u043a\u0443\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 RUN python3.6 -m venv tmp_venv --clear &amp;&amp; \\ . tmp_venv\/bin\/activate &amp;&amp; \\ python3.6 -m pip install pip==21.3.1 &amp;&amp; \\ pip install -r \/tmp\/build\/requirements.txt &amp;&amp; \\ deactivate &amp;&amp; \\ cd tmp_venv &amp;&amp; \\ zip -rq \/app\/dependencies.zip * &amp;&amp; \\ rm -rf \/tmp\/build \/app\/tmp_venv   # \u043a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u0441\u043a\u0440\u0438\u043f\u0442\u044b \u0441 \u043a\u043e\u0434\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f COPY py_scripts \/app\/py_scripts   ENTRYPOINT [\"\/bin\/bash\"] <\/code><\/pre>\n<p>\u0421\u0430\u0431\u043c\u0438\u0442\u0438\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u043d\u043e\u043c \u0440\u0435\u0436\u0438\u043c\u0435 \u0447\u0435\u0440\u0435\u0437 YARN.\u00a0<\/p>\n<p>\u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u043e Spark \u0432 Docker \u0443\u0434\u043e\u0431\u043d\u043e \u043f\u043e \u043c\u043d\u043e\u0433\u0438\u043c \u043f\u0440\u0438\u0447\u0438\u043d\u0430\u043c:<\/p>\n<ul>\n<li>\n<p>\u041f\u0440\u043e\u0441\u0442\u043e\u0442\u0430 \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f. \u041f\u0440\u0438 \u043f\u0435\u0440\u0435\u0435\u0437\u0434\u0435 \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e Spark \u043d\u0435\u0442 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c \u0430\u043f\u0433\u0440\u0435\u0439\u0434 \u043a\u043b\u0430\u0441\u0442\u0435\u0440\u0430 Hadoop \u0438 \u043f\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u0442\u044c, \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442 \u043b\u0438 \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 \u043d\u043e\u0432\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<\/li>\n<li>\n<p>\u0423\u0447\u0430\u0441\u0442\u0438\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u043e\u0432 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0432\u044b\u043a\u0430\u0442\u043a\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439 \u043d\u0430 \u043f\u0440\u043e\u0434 \u0441\u0432\u043e\u0434\u0438\u0442\u0441\u044f \u043a \u043c\u0438\u043d\u0438\u043c\u0443\u043c\u0443: \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441 \u0433\u043e\u0442\u043e\u0432\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u043e\u043c. \u041e\u0441\u0442\u0430\u0435\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0441\u0442\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0440\u0435\u0432\u044c\u044e, \u043d\u0430\u0436\u0430\u0442\u044c \u0430\u043f\u0440\u0443\u0432, \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u043e\u0431\u0435\u0436\u0438\u0442 \u0432 Airflow \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u044f\u0446\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>\u041d\u0430 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0447\u0438\u043a\u0430 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u0438\u043c\u0435\u0442\u044c Docker, \u0447\u0442\u043e\u0431\u044b \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u0441\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u043e\u0431\u0440\u0430\u0437\u044b \u0438 \u0442\u0430\u043a \u0436\u0435 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u0438 \u0438\u0445 \u043f\u043e\u043c\u043e\u0449\u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c Spark-\u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438.<\/p>\n<\/li>\n<li>\n<p>Kuber Friendly: \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0430 Kubernetes (\u043f\u0440\u043e\u0432\u0435\u0440\u044f\u043b\u0438 \u043f\u0440\u0438 \u043f\u0438\u043b\u043e\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0438 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 Spark on K8s).<\/p>\n<\/li>\n<li>\n<p>\u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0440\u0441\u0438\u0439 Spark \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e.<\/p>\n<\/li>\n<\/ul>\n<p>\u041d\u043e \u0443 \u044d\u0442\u043e\u0433\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0430 \u0435\u0441\u0442\u044c \u043e\u0434\u0438\u043d \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a: \u043d\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0443\u0434\u043e\u0431\u043d\u043e\u0433\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u0430 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c Spark \u0432 docker-\u043e\u0431\u0440\u0430\u0437\u0435 \u0438\u0437 Airflow\u00a0 \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432.\u00a0<\/p>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 \u043d\u0435 \u043f\u043e\u0434\u043e\u0448\u043b\u0438 \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u0440\u0435\u0448\u0435\u043d\u0438\u044f<\/h2>\n<p>\u0422\u0430\u043a \u043a\u0430\u043a \u043c\u044b \u0434\u0435\u0440\u0436\u0438\u043c Spark \u0432 Docker \u0438 \u043d\u0435 \u0445\u043e\u0442\u0438\u043c \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u043f\u0430\u043a\u0435\u0442\u044b \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Spark \u043d\u0430 \u0432\u043e\u0440\u043a\u0435\u0440\u044b Airflow, \u0442\u043e \u043c\u044b \u043d\u0435 \u043c\u043e\u0436\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0435 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/airflow.apache.org\/docs\/apache-airflow-providers-apache-spark\/stable\/index.html\"><u>Airflow Spark Provider<\/u><\/a> SparkSubmitOperator,<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\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-374802","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/374802","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=374802"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/374802\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=374802"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=374802"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=374802"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}