{"id":491095,"date":"2026-08-16T21:58:27","date_gmt":"2026-08-16T21:58:27","guid":{"rendered":"https:\/\/savepearlharbor.com\/?p=491095"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=491095","title":{"rendered":"\u0421 \u043d\u0443\u043b\u044f \u0434\u043e Junior DevOps \u0432 2026 \u0433\u043e\u0434\u0443. \u0427\u0430\u0441\u0442\u044c 7.2. Ansible \u0432 DevOps: Docker, Kubernetes, CI\/CD \u0438 Terraform"},"content":{"rendered":"<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>\u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0438\u0441\u044c \u0441 \u043e\u0441\u043d\u043e\u0432\u0430\u043c\u0438 Ansible, \u0441\u043e\u0437\u0434\u0430\u043b\u0438 Inventory, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 Playbook \u0438 \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Roles, Templates, Variables \u0438 Ansible Vault. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 Ansible \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.\u0412  \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 Ansible \u0440\u0435\u0434\u043a\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 Terraform, Docker, Kubernetes, GitHub Actions, GitLab CI \u0438\u043b\u0438 Jenkins.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u0448\u0438\u043d\u044b \u0438 \u0441\u0435\u0442\u0438, Ansible \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0438\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435, Docker \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b, \u0430 CI\/CD \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u043c \u0438\u0437\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0433\u0434\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f Ansible \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 DevOps-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435.<\/p>\n<hr\/>\n<h2>Terraform + Ansible: \u0434\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u2014 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438<\/h2>\n<pre><code>Terraform\u25bc\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b\u251c\u2500\u2500 Network\u251c\u2500\u2500 Virtual Machine\u251c\u2500\u2500 Disk\u2514\u2500\u2500 Load Balancer\u2502\u25bcAnsible\u251c\u2500\u2500 Users\u251c\u2500\u2500 Packages\u251c\u2500\u2500 Docker\u251c\u2500\u2500 Nginx\u251c\u2500\u2500 Configuration\u2514\u2500\u2500 Application<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:87px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Terraform \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0437\u0430 <strong>Infrastructure as Code<\/strong>, \u0430 Ansible \u2014 \u0437\u0430 <strong>Configuration Management<\/strong>. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443:<\/p>\n<pre><code>resource \"...\" \"web\" {  # \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u044b}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0435\u0451 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Ansible \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Docker:<\/p>\n<pre><code class=\"yaml\">- name: Install Docker  hosts: web  become: true  tasks:    - name: Install Docker      ansible.builtin.apt:        name: docker.io        state: present<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c:<\/p>\n<pre><code>Terraform \u2192 Infrastructure \u2192 Ansible \u2192 Configuration<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>Terraform \u2192 Ansible<\/h2>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u0441\u043e\u0437\u0434\u0430\u043b:<\/p>\n<pre><code>web-01 \u2192 10.10.1.10web-02 \u2192 10.10.1.11web-03 \u2192 10.10.1.12<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Ansible \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0438 \u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u043f\u043e\u043d\u044f\u0442\u044c, \u043a \u043a\u0430\u043a\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f. \u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 Inventory \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u041e\u0434\u043d\u0430\u043a\u043e \u0432 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c. \u0415\u0441\u043b\u0438 Terraform \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a IP-\u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u0417\u0434\u0435\u0441\u044c \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f <strong>Dynamic Inventory<\/strong>.<\/p>\n<hr\/>\n<h2>Dynamic Inventory<\/h2>\n<p>\u041e\u0431\u044b\u0447\u043d\u044b\u0439 Inventory \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code>[web]10.10.1.1010.10.1.11[database]10.10.2.10<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u043e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f:<\/p>\n<pre><code>10.10.1.10 \u2192 \u0443\u0434\u0430\u043b\u0451\u043d10.10.1.11 \u2192 \u0443\u0434\u0430\u043b\u0451\u043d10.10.1.20 \u2192 \u0441\u043e\u0437\u0434\u0430\u043d10.10.1.21 \u2192 \u0441\u043e\u0437\u0434\u0430\u043d<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 Inventory \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c, Ansible \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. <strong>Dynamic Inventory<\/strong> \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code>Cloud Provider\u25bcDynamic Inventory\u25bcAnsible<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c:<\/p>\n<ul>\n<li>\n<p>AWS;<\/p>\n<\/li>\n<li>\n<p>Azure;<\/p>\n<\/li>\n<li>\n<p>Google Cloud;<\/p>\n<\/li>\n<li>\n<p>Kubernetes;<\/p>\n<\/li>\n<li>\n<p>VMware;<\/p>\n<\/li>\n<li>\n<p>\u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.<\/p>\n<\/li>\n<\/ul>\n<p>\u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445.<\/p>\n<hr\/>\n<h2>Provisioners: \u043f\u043e\u0447\u0435\u043c\u0443 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043e<\/h2>\n<p>Terraform \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <strong>Provisioners<\/strong>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code>provisioner \"remote-exec\" {  inline = [    \"sudo apt update\",    \"sudo apt install nginx -y\"  ]}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u043e: Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u041d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0443\u0447\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c. Provisioners:<\/p>\n<ul>\n<li>\n<p>\u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c;<\/p>\n<\/li>\n<li>\n<p>\u0445\u0443\u0436\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438;<\/p>\n<\/li>\n<li>\n<p>\u043c\u043e\u0433\u0443\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u043d\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043c\u0435\u0448\u0438\u0432\u0430\u044e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438 \u0435\u0451 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>Provisioners \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u043d\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432.<\/p>\n<hr\/>\n<h2>Terraform \u2192 Ansible<\/h2>\n<p>\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0442 Terraform \u043a Ansible. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0435\u0433\u043e IP-\u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 Inventory. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code>Terraform\u25bc192.168.56.101\u25bcAnsible Inventory\u25bcAnsible Playbook<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Inventory:<\/p>\n<pre><code class=\"yaml\">all:  children:    web:      hosts:        web-01:          ansible_host:          192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <strong>Dynamic Inventory<\/strong>.<\/p>\n<hr\/>\n<h3>\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442: Ansible + Docker Compose + Molecule + CI\/CD<\/h3>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0432\u0441\u0451 \u0438\u0437\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0432 \u043e\u0434\u0438\u043d \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u043e \u0443\u0436\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u043d\u044b\u0439 \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442. \u041d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043c\u0430\u043d\u0434 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441:<\/p>\n<pre><code>Developer\u25bcGit\u25bcGitHub Actions\u251c\u2500\u2500 ansible-lint\u251c\u2500\u2500 syntax check\u2514\u2500\u2500 Molecule       \u25bc  Ansible Role       \u25bc Ubuntu Server       \u2502        \u251c\u2500\u2500 Docker Engine       \u251c\u2500\u2500 Docker Compose v2       \u251c\u2500\u2500 deploy       \u2502       \u2514\u2500\u2500 \/opt\/myapp            \u2502            \u2514\u2500\u2500 Docker Compose            \u251c\u2500\u2500 Nginx            \u251c\u2500\u2500 Redis            \u2514\u2500\u2500 PostgreSQL<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e:<\/p>\n<ul>\n<li>\n<p>\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0447\u0435\u0440\u0435\u0437 Ansible;<\/p>\n<\/li>\n<li>\n<p>\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c <code>--check<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 <code>ansible-lint<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u043b\u044c \u0447\u0435\u0440\u0435\u0437 Molecule;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 GitHub Actions.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043f\u043b\u043e\u0439. Molecule \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u043e\u043b\u0438 \u0432 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c Docker-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 Docker Compose deployment \u2014 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 Ubuntu-\u043c\u0430\u0448\u0438\u043d\u0435. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c Docker daemon \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.<\/p>\n<h4>\u0427\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f<\/h4>\n<p>\u0414\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\n<p>Control Node \u0441 Linux;<\/p>\n<\/li>\n<li>\n<p>Ansible;<\/p>\n<\/li>\n<li>\n<p>Git;<\/p>\n<\/li>\n<li>\n<p>Docker \u043d\u0430 Control Node \u2014 \u043e\u043d \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f Molecule;<\/p>\n<\/li>\n<li>\n<p>Ubuntu Managed Node;<\/p>\n<\/li>\n<li>\n<p>SSH-\u0434\u043e\u0441\u0442\u0443\u043f \u043a Managed Node;<\/p>\n<\/li>\n<li>\n<p>GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<\/li>\n<\/ul>\n<p>\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 Managed Node \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043e\u0431\u043b\u0430\u0447\u043d\u0443\u044e VM \u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443 VirtualBox.<\/p>\n<p>\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c:<\/p>\n<pre><code>Control Node192.168.56.1Managed Node192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0438.<\/p>\n<hr\/>\n<h3>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433:<\/p>\n<pre><code class=\"bash\">mkdir ansible-docker-democd ansible-docker-demo<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<pre><code>ansible-docker-demo\/\u251c\u2500\u2500 ansible.cfg\u251c\u2500\u2500 requirements.yml\u251c\u2500\u2500 inventory\/\u2502   \u2514\u2500\u2500 hosts.yml\u251c\u2500\u2500 playbooks\/\u2502   \u2514\u2500\u2500 site.yml\u251c\u2500\u2500 roles\/\u2502   \u2514\u2500\u2500 docker_app\/\u2502       \u251c\u2500\u2500 defaults\/\u2502       \u2502   \u2514\u2500\u2500 main.yml\u2502       \u251c\u2500\u2500 handlers\/\u2502       \u2502   \u2514\u2500\u2500 main.yml\u2502       \u251c\u2500\u2500 tasks\/\u2502       \u2502   \u251c\u2500\u2500 main.yml\u2502       \u2502   \u2514\u2500\u2500 deploy.yml\u2502       \u251c\u2500\u2500 templates\/\u2502       \u2502   \u2514\u2500\u2500 compose.yml.j2\u2502       \u2514\u2500\u2500 meta\/\u2502           \u2514\u2500\u2500 main.yml\u251c\u2500\u2500 molecule\/\u2502   \u2514\u2500\u2500 docker_app\/\u2502       \u251c\u2500\u2500 converge.yml\u2502       \u251c\u2500\u2500 molecule.yml\u2502       \u2514\u2500\u2500 verify.yml\u2514\u2500\u2500 .github\/    \u2514\u2500\u2500 workflows\/      \u2514\u2500\u2500 ansible.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e Role.<\/p>\n<p>Ansible Role \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0435\u0451 \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 Playbook. Ansible \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Roles \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438.<\/p>\n<hr\/>\n<h3>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438<\/h3>\n<p>\u041d\u0430 Control Node \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 Python:<\/p>\n<pre><code class=\"bash\">python3 -m venv .venvsource .venv\/bin\/activate<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b:<\/p>\n<pre><code class=\"bash\">pip install \\  ansible-core \\  ansible-lint \\  molecule \\  molecule-plugins[docker]<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ansible-lint<\/code> \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 Ansible-\u043a\u043e\u0434\u0430, \u0430 Molecule \u2014 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Roles \u0438 Playbook. Ansible \u043e\u0442\u043d\u043e\u0441\u0438\u0442 \u043e\u0431\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 Ansible-\u043a\u043e\u0434\u0430. \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>requirements.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">---collections:  - name: community.docker<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e:<\/p>\n<pre><code class=\"bash\">ansible-galaxy collection install -r requirements.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f <code>community.docker<\/code> \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 <code>ansible-core<\/code>. \u041e\u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, <code>community.docker.docker_compose_v2<\/code>.<\/p>\n<hr\/>\n<h3>\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c Ansible<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>ansible.cfg<\/code>:<\/p>\n<pre><code>[defaults]inventory = inventory\/hosts.ymlroles_path = roleshost_key_checking = Falseinterpreter_python = auto_silent<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <code>roles_path<\/code> \u0433\u043e\u0432\u043e\u0440\u0438\u0442 Ansible, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 Roles. \u0422\u0435\u043f\u0435\u0440\u044c Inventory.<\/p>\n<h4>inventory\/hosts.yml<\/h4>\n<pre><code class=\"yaml\">---all:  children:    web:      hosts:        web-01:          ansible_host: 192.168.56.101          ansible_user: ubuntu<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:<\/p>\n<pre><code class=\"bash\">ansible-inventory --graph<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e:<\/p>\n<pre><code>@all:  |--@ungrouped:  |--@web:  |    |--web-01<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h3>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c SSH<\/h3>\n<p>\u0414\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Playbook \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043e\u0431\u044b\u0447\u043d\u043e\u0435 SSH-\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:<\/p>\n<pre><code class=\"bash\">ssh ubuntu@192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c Ansible:<\/p>\n<pre><code class=\"bash\">ansible web -m ansible.builtin.ping<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:<\/p>\n<pre><code>web-01 | SUCCESS =&gt; {    \"changed\": false,    \"ping\": \"pong\"}<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c <code>ping<\/code> \u2014 \u043d\u0435 ICMP ping. \u041c\u043e\u0434\u0443\u043b\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043b\u0438 Ansible \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.<\/p>\n<hr\/>\n<h2>\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Docker Engine \u0438 Compose v2<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c Managed Node. Docker \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c Docker Engine \u043d\u0430 Ubuntu \u0447\u0435\u0440\u0435\u0437 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 APT-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. \u0412 \u0441\u043e\u0441\u0442\u0430\u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0445\u043e\u0434\u044f\u0442 Docker Engine, Docker CLI, <a href=\"http:\/\/containerd.io\" rel=\"noopener noreferrer nofollow\"><code>containerd.io<\/code><\/a>, Buildx \u0438 Docker Compose plugin. \u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Ubuntu-\u043f\u0430\u043a\u0435\u0442 <a href=\"http:\/\/docker.io\" rel=\"noopener noreferrer nofollow\"><code>docker.io<\/code><\/a> \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0434\u0435\u044f\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 Compose.<\/p>\n<p>\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u044b:<\/p>\n<pre><code>docker-cedocker-ce-clicontainerd.iodocker-buildx-plugindocker-compose-plugin<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c <code>playbooks\/site.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">---- name: Prepare Docker host  hosts: web  become: true  tasks:    - name: Install prerequisites      ansible.builtin.apt:        name:          - ca-certificates          - curl        state: present        update_cache: true    - name: Create Docker keyrings directory      ansible.builtin.file:        path: \/etc\/apt\/keyrings        state: directory        mode: \"0755\"    - name: Download Docker GPG key      ansible.builtin.get_url:        url: https:\/\/download.docker.com\/linux\/ubuntu\/gpg        dest: \/etc\/apt\/keyrings\/docker.asc        mode: \"0644\"    - name: Configure Docker repository      ansible.builtin.copy:        dest: \/etc\/apt\/sources.list.d\/docker.sources        mode: \"0644\"        content: |          Types: deb          URIs: https:\/\/download.docker.com\/linux\/ubuntu          Suites: {{ ansible_facts.distribution_release }}          Components: stable          Architectures: {{ ansible_facts.architecture }}          Signed-By: \/etc\/apt\/keyrings\/docker.asc    - name: Install Docker      ansible.builtin.apt:        name:          - docker-ce          - docker-ce-cli          - containerd.io          - docker-buildx-plugin          - docker-compose-plugin        state: present        update_cache: true    - name: Start Docker      ansible.builtin.systemd:        name: docker        state: started        enabled: true<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c:<\/p>\n<pre><code class=\"bash\">ansible-playbook playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c Docker:<\/p>\n<pre><code class=\"bash\">ansible web \\  -m ansible.builtin.command \\  -a \"docker --version\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418 Compose:<\/p>\n<pre><code class=\"bash\">ansible web \\  -m ansible.builtin.command \\  -a \"docker compose version\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Docker Compose v2 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0447\u0435\u0440\u0435\u0437 CLI plugin <code>docker compose<\/code>. \u0418\u043c\u0435\u043d\u043d\u043e \u044d\u0442\u043e\u0442 plugin \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044e <code>community.docker.docker_compose_v2<\/code>. \u0412 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043d\u0438\u0435 \u0434\u043b\u044f \u043c\u043e\u0434\u0443\u043b\u044f \u2014 Docker Compose plugin \u0432\u0435\u0440\u0441\u0438\u0438 2.18.0 \u0438\u043b\u0438 \u043d\u043e\u0432\u0435\u0435. \u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e Docker:<\/p>\n<pre><code class=\"bash\">ansible web \\  -m ansible.builtin.command \\  -a \"docker run --rm hello-world\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Docker \u0442\u0430\u043a\u0436\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 <code>hello-world<\/code> \u043a\u0430\u043a \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0439 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438.<\/p>\n<hr\/>\n<h2>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f deploy<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0432 Role. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>roles\/docker_app\/defaults\/main.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---app_user: deployapp_group: deployapp_dir: \/opt\/myapp<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c <code>roles\/docker_app\/tasks\/main.yml<\/code>:<\/p>\n<pre><code class=\"yaml\">---- name: Create application group  ansible.builtin.group:    name: \"{{ app_group }}\"    state: present- name: Create application user  ansible.builtin.user:    name: \"{{ app_user }}\"    group: \"{{ app_group }}\"    groups: docker    append: true    shell: \/bin\/bash    create_home: true- name: Create application directory  ansible.builtin.file:    path: \"{{ app_dir }}\"    state: directory    owner: \"{{ app_user }}\"    group: \"{{ app_group }}\"    mode: \"0755\"- name: Deploy Compose file  ansible.builtin.template:    src: compose.yml.j2    dest: \"{{ app_dir }}\/compose.yml\"    owner: \"{{ app_user }}\"    group: \"{{ app_group }}\"    mode: \"0644\"    notify: Restart application- name: Deploy application  ansible.builtin.include_tasks:    file: deploy.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c Ansible:<\/p>\n<ol>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u0451\u0442 <code>deploy<\/code>;<\/p>\n<\/li>\n<li>\n<p>\u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0434\u0430\u0451\u0442 Compose;<\/p>\n<\/li>\n<li>\n<p>\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043d\u0430\u0431\u043e\u0440 \u0437\u0430\u0434\u0430\u0447 \u0434\u043b\u044f deployment.<\/p>\n<\/li>\n<\/ol>\n<p>\u0427\u043b\u0435\u043d\u0441\u0442\u0432\u043e \u0432 \u0433\u0440\u0443\u043f\u043f\u0435 <code>docker<\/code> \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438, \u043d\u043e \u0432\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0435\u0433\u043e \u043f\u043e\u0441\u043b\u0435\u0434\u0441\u0442\u0432\u0438\u044f: \u0434\u043e\u0441\u0442\u0443\u043f \u043a Docker daemon \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u043f\u0440\u0438\u0432\u0438\u043b\u0435\u0433\u0438\u0439, \u0441\u043e\u043f\u043e\u0441\u0442\u0430\u0432\u0438\u043c\u044b\u0439 \u0441 root. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 production \u043c\u043e\u0434\u0435\u043b\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043a Docker \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<hr\/>\n<h2>\u0421\u043e\u0437\u0434\u0430\u0451\u043c Docker Compose<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>roles\/docker_app\/templates\/compose.yml.j2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">services:  web:    image: nginx:alpine    ports:      - \"80:80\"    restart: unless-stopped  redis:    image: redis:alpine    restart: unless-stopped  postgres:    image: postgres:16    environment:      POSTGRES_DB: example      POSTGRES_USER: app      POSTGRES_PASSWORD: example      restart: unless-stopped<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u044d\u0442\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e. \u0412 production \u043f\u0430\u0440\u043e\u043b\u044c PostgreSQL \u043d\u0435\u043b\u044c\u0437\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 Git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438. \u0417\u0434\u0435\u0441\u044c \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Ansible Vault, \u0432\u043d\u0435\u0448\u043d\u0438\u0439 Secret Manager \u0438\u043b\u0438 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c \u0441\u0435\u043a\u0440\u0435\u0442\u043e\u0432 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0439 \u043f\u043b\u0430\u0442\u0444\u043e\u0440\u043c\u044b.<\/p>\n<hr\/>\n<h2>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Compose \u0447\u0435\u0440\u0435\u0437 Ansible<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>roles\/docker_app\/tasks\/deploy.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---- name: Start Docker Compose application  community.docker.docker_compose_v2:    project_src: \"{{ app_dir }}\"    state: present<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442. \u041d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c:<\/p>\n<pre><code class=\"yaml\">ansible.builtin.command:  cmd: docker compose up -d<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0412\u043c\u0435\u0441\u0442\u043e \u044d\u0442\u043e\u0433\u043e \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u043c \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<pre><code class=\"yaml\">community.docker.docker_compose_v2:  project_src: \/opt\/myapp  state: present<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u043e\u0434\u0443\u043b\u044c <code>community.docker.docker_compose_v2<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f multi-container Docker applications \u0447\u0435\u0440\u0435\u0437 Docker Compose CLI plugin. \u0412 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0442\u0430\u043a\u0436\u0435 \u0443\u043a\u0430\u0437\u0430\u043d\u043e, \u0447\u0442\u043e \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441 \u0442\u0435\u043c\u0438 \u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438 \u043e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u043d\u043e.<\/p>\n<p>\u0421\u0442\u0430\u0440\u044b\u0439 <code>community.docker.docker_compose<\/code> \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0430\u043b\u0441\u044f \u0434\u043b\u044f Compose v1 \u0438 \u0443\u0434\u0430\u043b\u0451\u043d \u0438\u0437 <code>community.docker<\/code> \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u0432\u0435\u0440\u0441\u0438\u0438 4.0.0. \u0414\u043b\u044f \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>docker_compose_v2<\/code>.<\/p>\n<hr\/>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Handler<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>roles\/docker_app\/handlers\/main.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---- name: Restart application  community.docker.docker_compose_v2:    project_src: \"{{ app_dir }}\"    state: restarted<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Handler \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0437\u0432\u0430\u043d \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f Compose-\u0444\u0430\u0439\u043b\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<pre><code>compose.yml     \u2502     \u25bc\u0418\u0437\u043c\u0435\u043d\u0438\u043b\u0441\u044f?  \u250c\u2500\u2500\u2534\u2500\u2500\u2510  \u2502     \u2502 \u0414\u0430     \u041d\u0435\u0442  \u2502     \u2502  \u25bc     \u25bcRestart \u041d\u0438\u0447\u0435\u0433\u043e<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0430\u043c\u043d\u043e\u0433\u043e \u043b\u0443\u0447\u0448\u0435, \u0447\u0435\u043c \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u0435\u0440\u0435\u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438 \u043a\u0430\u0436\u0434\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 Playbook.<\/p>\n<hr\/>\n<h2>\u041f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0435\u043c Role<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c <code>playbooks\/site.yml<\/code> \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u043c:<\/p>\n<pre><code class=\"yaml\">---- name: Prepare Docker host  hosts: web  become: true  tasks:    - name: Install prerequisites      ansible.builtin.apt:        name:          - ca-certificates          - curl        state: present        update_cache: true    - name: Create Docker keyrings directory      ansible.builtin.file:        path: \/etc\/apt\/keyrings        state: directory        mode: \"0755\"    - name: Download Docker GPG key      ansible.builtin.get_url:        url: https:\/\/download.docker.com\/linux\/ubuntu\/gpg        dest: \/etc\/apt\/keyrings\/docker.asc        mode: \"0644\"    - name: Configure Docker repository      ansible.builtin.copy:        dest: \/etc\/apt\/sources.list.d\/docker.sources        mode: \"0644\"        content: |          Types: deb          URIs: https:\/\/download.docker.com\/linux\/ubuntu          Suites: {{ ansible_facts.distribution_release }}          Components: stable          Architectures: {{ ansible_facts.architecture }}          Signed-By: \/etc\/apt\/keyrings\/docker.asc    - name: Install Docker      ansible.builtin.apt:        name:          - docker-ce          - docker-ce-cli          - containerd.io          - docker-buildx-plugin          - docker-compose-plugin        state: present        update_cache: true    - name: Start Docker      ansible.builtin.systemd:        name: docker        state: started        enabled: true    - name: Deploy application      ansible.builtin.include_role:        name: docker_app<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0435\u0441\u044c deployment \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u043e\u0439 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439:<\/p>\n<pre><code class=\"bash\">ansible-playbook playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442<\/h2>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b:<\/p>\n<pre><code class=\"bash\">ansible web \\  -m ansible.builtin.command \\  -a \"docker compose -f \/opt\/myapp\/compose.yml ps\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043e\u043b\u0436\u043d\u044b \u043f\u043e\u044f\u0432\u0438\u0442\u044c\u0441\u044f:<\/p>\n<pre><code>webredispostgres<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443:<\/p>\n<pre><code class=\"bash\">ssh ubuntu@192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c:<\/p>\n<pre><code class=\"bash\">cd \/opt\/myappdocker compose ps<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c Nginx:<\/p>\n<pre><code class=\"bash\">curl http:\/\/192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432\u0441\u0451 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043e \u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0441\u0435\u0440\u0432\u0435\u0440 \u0432\u0435\u0440\u043d\u0451\u0442 HTML \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b Nginx. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448 deployment \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a:<\/p>\n<pre><code>Terraform\u25bcUbuntu VM\u25bcAnsible\u251c\u2500\u2500 Docker\u251c\u2500\u2500 deploy\u2514\u2500\u2500 \/opt\/myapp        \u2502        \u25bc  Docker Compose   \u250c\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2510   \u25bc    \u25bc    \u25bcNginx Redis PostgreSQL<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u043d\u043e\u0441\u0442\u044c<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043e\u0434\u043d\u0430 \u0438\u0437 \u0441\u0430\u043c\u044b\u0445 \u0432\u0430\u0436\u043d\u044b\u0445 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Playbook \u0435\u0449\u0451 \u0440\u0430\u0437:<\/p>\n<pre><code class=\"bash\">ansible-playbook playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0451\u043d\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u0447\u0438:<\/p>\n<pre><code>changed &gt; 0<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u0442\u043e\u0440\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u0434\u043e\u043b\u0436\u043d\u043e \u0437\u043d\u0430\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0443\u043c\u0435\u043d\u044c\u0448\u0438\u0442\u044c\u0441\u044f, \u0430 \u043f\u0440\u0438 \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 deployment \u0434\u043e\u043b\u0436\u0435\u043d \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u044c\u0441\u044f \u0431\u0435\u0437 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u0433\u043e \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432. \u041f\u043e\u0447\u0435\u043c\u0443 \u044d\u0442\u043e \u0432\u0430\u0436\u043d\u043e?<\/p>\n<p>\u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e Ansible \u043e\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442 \u0436\u0435\u043b\u0430\u0435\u043c\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435:<\/p>\n<pre><code>\u00ab\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c deploy \u0434\u043e\u043b\u0436\u0435\u043d \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c\u00bb<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0430 \u043d\u0435 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0439:<\/p>\n<pre><code>\u00ab\u0441\u043e\u0437\u0434\u0430\u0439 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f deploy\u00bb<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u043a Compose:<\/p>\n<pre><code>state: present<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u043e\u0437\u043d\u0430\u0447\u0430\u0435\u0442, \u0447\u0442\u043e \u043f\u0440\u043e\u0435\u043a\u0442 \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c\u0441\u044f \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0435\u043c \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0438. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f <code>community.docker.docker_compose_v2<\/code> \u043f\u0440\u044f\u043c\u043e \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0443 \u0438\u0434\u0435\u043c\u043f\u043e\u0442\u0435\u043d\u0442\u043d\u043e\u0433\u043e \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u043f\u0440\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e\u043c \u0437\u0430\u043f\u0443\u0441\u043a\u0435 \u0441 \u0442\u0435\u043c\u0438 \u0436\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430\u043c\u0438.<\/p>\n<hr\/>\n<h2>\u0418\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c Check Mode<\/h2>\n<p>\u041f\u0435\u0440\u0435\u0434 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c:<\/p>\n<pre><code class=\"bash\">ansible-playbook \\  playbooks\/site.yml \\  --check \\  --diff<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f workflow:<\/p>\n<pre><code>\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u25bc--check --diff\u25bc\u041f\u0440\u043e\u0432\u0435\u0440\u043a\u0430\u25bcReview\u25bc\u041f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>--check<\/code> \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u0435\u043d \u043f\u0440\u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 production-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439.<\/p>\n<p>\u041e\u0434\u043d\u0430\u043a\u043e \u043d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c Check Mode \u043a\u0430\u043a \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u0443\u044e \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u044e \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0438\u0434\u0435\u043d\u0442\u0438\u0447\u043d\u043e: \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u043a\u0430 check mode \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e\u0433\u043e \u043c\u043e\u0434\u0443\u043b\u044f \u0438 \u0435\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441 \u0432\u043d\u0435\u0448\u043d\u0438\u043c\u0438 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u043c\u0438.<\/p>\n<hr\/>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c ansible-lint<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0430\u043c\u043e\u0433\u043e Ansible-\u043a\u043e\u0434\u0430. \u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c:<\/p>\n<pre><code class=\"bash\">ansible-lint .<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p><code>ansible-lint<\/code> \u0430\u043d\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u0442 Playbook \u0438 Roles \u0438 \u0432\u044b\u044f\u0432\u043b\u044f\u0435\u0442 \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u0438 \u0438 \u043d\u0430\u0440\u0443\u0448\u0435\u043d\u0438\u044f \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0445 \u043f\u0440\u0430\u043a\u0442\u0438\u043a. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u044e\u0442 \u043d\u0435\u043e\u043f\u0440\u0430\u0432\u0434\u0430\u043d\u043d\u043e\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 <code>shell<\/code> \u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0443\u0441\u043b\u043e\u0432\u0438\u044f\u0445. \u0415\u0441\u043b\u0438 lint \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u043e\u0431 \u043e\u0448\u0438\u0431\u043a\u0430\u0445, \u043b\u0443\u0447\u0448\u0435 \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c \u0441\u0430\u043c \u043a\u043e\u0434, \u0430 \u043d\u0435 \u0441\u0440\u0430\u0437\u0443 \u043e\u0442\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0438\u043b\u0430.<\/p>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u043c\u0435\u0441\u0442\u043e:<\/p>\n<pre><code class=\"yaml\">- name: Restart service  ansible.builtin.shell:    systemctl restart nginx<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u043f\u0440\u0435\u0434\u043f\u043e\u0447\u0442\u0438\u0442\u0435\u043b\u044c\u043d\u0435\u0435:<\/p>\n<pre><code class=\"yaml\">- name: Restart service  ansible.builtin.service:    name: nginx    state: restarted<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0437\u0430\u043f\u0443\u0441\u043a Compose \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u043c\u043e\u0434\u0443\u043b\u0435\u043c <code>community.docker.docker_compose_v2<\/code>, \u0430 \u043d\u0435 \u0447\u0435\u0440\u0435\u0437 <code>shell<\/code>.<\/p>\n<hr\/>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Molecule<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u2014 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 Role. Molecule \u043d\u0443\u0436\u0435\u043d \u043d\u0435 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0430\u043c\u043e\u0433\u043e production-\u0441\u0435\u0440\u0432\u0435\u0440\u0430, \u0430 \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e Role \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f. \u0412 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 Role \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430:<\/p>\n<pre><code>deploy userapplication directorycompose.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Docker Engine \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0441\u0442\u044c\u044e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e Playbook. \u0422\u0430\u043a\u043e\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0438 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u043e:<\/p>\n<pre><code>Playbook\u251c\u2500\u2500 Docker host preparation\u2502\u2514\u2500\u2500 docker_app Role    \u251c\u2500\u2500 user    \u251c\u2500\u2500 directory    \u2514\u2500\u2500 Compose configuration<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h3>\u041a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044f Molecule<\/h3>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>molecule\/docker_app\/molecule.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---driver:  name: dockerplatforms:  - name: instance    image: ubuntu:24.04    pre_build_image: trueprovisioner:  name: ansibleverifier:  name: ansible<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c Molecule \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442 Docker \u043a\u0430\u043a driver. \u0421\u0430\u043c Docker \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043d\u0430 Control Node, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u0442\u0435\u0441\u0442\u043e\u0432\u0430\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u0431\u0443\u0434\u0435\u0442 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c\u0441\u044f \u0432 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445.<\/p>\n<hr\/>\n<h2>Converge<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>molecule\/docker_app\/converge.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---- name: Converge  hosts: all  become: true  vars:    molecule_test: true  roles:    - role: docker_app<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u043e \u0437\u0434\u0435\u0441\u044c \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u0435\u0442 \u0432\u0430\u0436\u043d\u044b\u0439 \u0432\u043e\u043f\u0440\u043e\u0441. Role \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0437\u0430\u0434\u0430\u0447\u0443:<\/p>\n<pre><code class=\"yaml\">community.docker.docker_compose_v2<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u043d\u0435\u0451 \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0435 \u043f\u043e\u0442\u0440\u0435\u0431\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u0431\u044b Docker CLI \u0438 Compose plugin. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c production deployment \u0432\u043d\u0443\u0442\u0440\u0438 \u043e\u0431\u044b\u0447\u043d\u043e\u0433\u043e Molecule-\u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430. \u0412\u043d\u0435\u0441\u0451\u043c \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0432 <code>roles\/docker_app\/tasks\/main.yml<\/code>.<\/p>\n<pre><code class=\"yaml\">---- name: Create application user  ansible.builtin.user:    name: \"{{ app_user }}\"    group: \"{{ app_group }}\"    groups: docker    append: true    shell: \/bin\/bash    create_home: true- name: Create application directory  ansible.builtin.file:    path: \"{{ app_dir }}\"    state: directory    owner: \"{{ app_user }}\"    group: \"{{ app_group }}\"    mode: \"0755\"- name: Deploy Compose file  ansible.builtin.template:    src: compose.yml.j2    dest: \"{{ app_dir }}\/compose.yml\"    owner: \"{{ app_user }}\"    group: \"{{ app_group }}\"    mode: \"0644\"- name: Deploy application  ansible.builtin.include_tasks:    file: deploy.yml  when: not molecule_test | default(false)<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c:<\/p>\n<pre><code>Production\u25bcuserdirectorycomposedeployment<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0430 Molecule:<\/p>\n<pre><code>Molecule\u25bcuserdirectorycompose<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e \u0435\u0441\u0442\u044c Molecule \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442 \u0441\u0430\u043c\u0443 Role, \u043d\u0435 \u043f\u043e\u0434\u043c\u0435\u043d\u044f\u044f production-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435.<\/p>\n<hr\/>\n<h2>\u0421\u043e\u0437\u0434\u0430\u0451\u043c Verify<\/h2>\n<p>\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>molecule\/docker_app\/verify.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">---- name: Verify  hosts: all  become: true  tasks:    - name: Check deploy user      ansible.builtin.getent:        database: passwd        key: deploy    - name: Check application directory      ansible.builtin.stat:        path: \/opt\/myapp      register: app_dir    - name: Assert application directory exists      ansible.builtin.assert:        that:          - app_dir.stat.exists          - app_dir.stat.isdir    - name: Check Compose file      ansible.builtin.stat:        path: \/opt\/myapp\/compose.yml      register: compose_file    - name: Assert Compose file exists      ansible.builtin.assert:        that:          - compose_file.stat.exists          - compose_file.stat.isreg<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0442\u0435\u0441\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442 \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430:<\/p>\n<pre><code>deploy \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442      +\/opt\/myapp \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442      +compose.yml \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c Molecule<\/h2>\n<p>\u0412\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u043c:<\/p>\n<pre><code class=\"bash\">molecule test<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>Molecule \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435, \u043f\u0440\u0438\u043c\u0435\u043d\u044f\u0435\u0442 Role, \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0438 \u0437\u0430\u0442\u0435\u043c \u0443\u043d\u0438\u0447\u0442\u043e\u0436\u0430\u0435\u0442 \u0442\u0435\u0441\u0442\u043e\u0432\u0443\u044e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443. \u0423\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>Create\u25bcPrepare\u25bcConverge\u25bcVerify\u25bcDestroy<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0434\u043d\u0430 \u0438\u0437 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u043d\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442, <code>molecule test<\/code> \u0437\u0430\u0432\u0435\u0440\u0448\u0430\u0435\u0442\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439. \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0430\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0430 Role \u0431\u0435\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f production-\u0441\u0435\u0440\u0432\u0435\u0440\u0430.<\/p>\n<hr\/>\n<h2>\u0427\u0442\u043e \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u0443\u0435\u0442 Molecule<\/h2>\n<p>\u0412\u0430\u0436\u043d\u043e \u043f\u043e\u043d\u0438\u043c\u0430\u0442\u044c \u0433\u0440\u0430\u043d\u0438\u0446\u044b \u0442\u0435\u0441\u0442\u0430. Molecule \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:<\/p>\n<pre><code>Role\u251c\u2500\u2500 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\u251c\u2500\u2500 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u2514\u2500\u2500 \u0441\u043e\u0437\u0434\u0430\u0451\u0442 Compose-\u0444\u0430\u0439\u043b<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 integration test \u043d\u0430 Ubuntu \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442:<\/p>\n<pre><code>Docker Engine      +Docker Compose      +Real Compose deployment      +    HTTP<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u042d\u0442\u043e \u043d\u0435 \u043d\u0435\u0434\u043e\u0441\u0442\u0430\u0442\u043e\u043a, \u0430 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u0443\u0440\u043e\u0432\u043d\u0435\u0439 \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f. \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f:<\/p>\n<pre><code>Unit\/Role-level\u25bcMoleculeIntegration\u25bcUbuntu VMProduction\u25bcReal servers<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c Git<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 Git.<\/p>\n<pre><code class=\"bash\">git initgit add .git commit -m \"Initial Ansible Docker deployment\"<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0421\u043e\u0437\u0434\u0430\u0451\u043c <code>.gitignore<\/code>:<\/p>\n<pre><code>.venv\/__pycache__\/*.retry.molecule\/<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0432 \u0431\u0443\u0434\u0443\u0449\u0435\u043c \u0432 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u043f\u043e\u044f\u0432\u044f\u0442\u0441\u044f Vault-\u0444\u0430\u0439\u043b\u044b, SSH-\u043a\u043b\u044e\u0447\u0438 \u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 \u0441\u0435\u043a\u0440\u0435\u0442\u044b, \u0438\u0445 \u0442\u0430\u043a\u0436\u0435 \u043d\u0435\u043b\u044c\u0437\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0439 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.<\/p>\n<hr\/>\n<h2>GitHub Actions<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438. \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c:<\/p>\n<pre><code>.github\/workflows\/ansible.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<pre><code class=\"yaml\">name: Ansible CIon:  push:  pull_request:jobs:  lint:    name: Ansible Lint    runs-on: ubuntu-latest    steps:      - name: Checkout        uses: actions\/checkout@v4      - name: Set up Python        uses: actions\/setup-python@v5        with:          python-version: \"3.12\"      - name: Install tools        run: |          python -m pip install --upgrade pip          pip install ansible-core ansible-lint molecule \"molecule-plugins[docker]\"      - name: Install Ansible collections        run: |          ansible-galaxy collection install -r requirements.yml      - name: Run ansible-lint        run: ansible-lint .  syntax:    name: Ansible Syntax Check    runs-on: ubuntu-latest    needs: lint    steps:      - name: Checkout        uses: actions\/checkout@v4      - name: Set up Python        uses: actions\/setup-python@v5        with:          python-version: \"3.12\"      - name: Install Ansible        run: |          python -m pip install --upgrade pip          pip install ansible-core      - name: Install collections        run: |          ansible-galaxy collection install -r requirements.yml      - name: Syntax check        run: |          ansible-playbook playbooks\/site.yml --syntax-check  molecule:    name: Molecule    runs-on: ubuntu-latest    needs: syntax    steps:      - name: Checkout        uses: actions\/checkout@v4      - name: Set up Python        uses: actions\/setup-python@v5        with:          python-version: \"3.12\"      - name: Install tools        run: |          python -m pip install --upgrade pip          pip install ansible-core ansible-lint molecule \"molecule-plugins[docker]\"      - name: Install collections        run: |          ansible-galaxy collection install -r requirements.yml      - name: Run Molecule        run: molecule test<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0441\u043b\u0435 \u043a\u0430\u0436\u0434\u043e\u0433\u043e <code>push<\/code> \u0438\u043b\u0438 <code>pull request<\/code> GitHub Actions \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442:<\/p>\n<pre><code>GitHub\u25bcCheckout\u25bcansible-lint\u25bcsyntax-check\u25bcMolecule<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0415\u0441\u043b\u0438 \u0445\u043e\u0442\u044f \u0431\u044b \u043e\u0434\u0438\u043d \u044d\u0442\u0430\u043f \u0437\u0430\u0432\u0435\u0440\u0448\u0438\u0442\u0441\u044f \u0441 \u043e\u0448\u0438\u0431\u043a\u043e\u0439, workflow \u0431\u0443\u0434\u0435\u0442 \u0441\u0447\u0438\u0442\u0430\u0442\u044c\u0441\u044f \u043d\u0435\u0443\u0441\u043f\u0435\u0448\u043d\u044b\u043c.<\/p>\n<hr\/>\n<h2>\u0414\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c CD<\/h2>\n<p>\u041f\u043e\u043a\u0430 GitHub Actions \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u2014 \u044d\u0442\u043e CI (Continuous Integration). \u0414\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0433\u043e CD (Continuous Delivery\/Deployment) runner \u0434\u043e\u043b\u0436\u0435\u043d \u0438\u043c\u0435\u0442\u044c \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a Managed Node. \u0412 \u043d\u0430\u0448\u0435\u043c \u0443\u0447\u0435\u0431\u043d\u043e\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 Managed Node \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439 \u0441\u0435\u0442\u0438. <code>192.168.56.101 .<\/code>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 GitHub-hosted runner \u043d\u0435 \u0441\u043c\u043e\u0436\u0435\u0442 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u043d\u0435\u043c\u0443 \u0431\u0435\u0437 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b. \u0412 production \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:<\/p>\n<ul>\n<li>\n<p>self-hosted GitHub Actions runner \u0432\u043d\u0443\u0442\u0440\u0438 \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u043e\u0439 \u0441\u0435\u0442\u0438;<\/p>\n<\/li>\n<li>\n<p>VPN \u0438\u043b\u0438 \u0434\u0440\u0443\u0433\u043e\u0439 \u0437\u0430\u0449\u0438\u0449\u0451\u043d\u043d\u044b\u0439 \u0441\u0435\u0442\u0435\u0432\u043e\u0439 \u043a\u0430\u043d\u0430\u043b;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0443\u0431\u043b\u0438\u0447\u043d\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0441\u0435\u0440\u0432\u0435\u0440 \u0441 \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u044b\u043c firewall;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0434\u0435\u043b\u044c\u043d\u0443\u044e deployment-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443.<\/p>\n<\/li>\n<\/ul>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 workflow \u0440\u0430\u0441\u0441\u043c\u0430\u0442\u0440\u0438\u0432\u0430\u0435\u043c \u043a\u0430\u043a \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 CD:<\/p>\n<pre><code>Lint\u25bcSyntax\u25bcMolecule\u25bcDeploy\u25bcProduction<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, deployment \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u043f\u0435\u0448\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432 \u0438 \u0442\u043e\u043b\u044c\u043a\u043e \u0434\u043b\u044f <code>main<\/code>. \u0423\u043f\u0440\u043e\u0449\u0451\u043d\u043d\u044b\u0439 job:<\/p>\n<pre><code class=\"yaml\">  deploy:    name: Deploy    runs-on: ubuntu-latest    needs:      - lint      - syntax      - molecule\\    if: github.ref == 'refs\/heads\/main' &amp;&amp; github.event_name == 'push'    steps:      - name: Checkout        uses: actions\/checkout@v4      - name: Set up Python        uses: actions\/setup-python@v5        with:          python-version: \"3.12\"      - name: Install Ansible        run: |          python -m pip install --upgrade pip          pip install ansible-core      - name: Install collections        run: |          ansible-galaxy collection install -r requirements.yml      - name: Configure SSH        run: |          mkdir -p ~\/.ssh          echo \"${{ secrets.DEPLOY_SSH_KEY }}\" &gt; ~\/.ssh\/id_ed25519          chmod 600 ~\/.ssh\/id_ed25519      - name: Deploy        run: |          ansible-playbook \\            -i inventory\/hosts.yml \\            playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041d\u043e \u043f\u0435\u0440\u0435\u0434 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u043a\u043e\u0433\u043e job \u0432 production \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c Inventory \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0441\u0435\u043a\u0440\u0435\u0442\u044b. SSH-\u043a\u043b\u044e\u0447, \u043f\u0430\u0440\u043e\u043b\u044c, \u0442\u043e\u043a\u0435\u043d\u044b \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0435\u043a\u0440\u0435\u0442\u044b \u043d\u0435\u043b\u044c\u0437\u044f \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0432 YAML workflow \u0438\u043b\u0438 Git-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438.<\/p>\n<hr\/>\n<h2>\u041f\u043e\u043b\u043d\u044b\u0439 pipeline<\/h2>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0430 \u0430\u0440\u0445\u0438\u0442\u0435\u043a\u0442\u0443\u0440\u0430 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code>                        GitHub                           \u25bc                      Pull Request                           \u25bc                         Lint                           \u25bc                         Syntax                           \u25bc                        Molecule                           \u25bc                       Code Review                           \u25bc                          Merge                           \u25bc                         Deploy                           \u25bc                        Ansible                           \u25bc                     Ubuntu Server                \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510                \u25bc          \u25bc          \u25bc             Docker      deploy     Config                \u25bc           Compose v2         \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2510         \u25bc      \u25bc      \u25bc       Nginx   Redis PostgreSQL<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u0442 \u0442\u043e\u0442 \u0436\u0435 \u043f\u0440\u0438\u043d\u0446\u0438\u043f, \u0447\u0442\u043e \u0438 \u043e\u0431\u044b\u0447\u043d\u044b\u0439 application code:<\/p>\n<pre><code>\u0418\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u25bcPull Request\u25bcLint\u25bcTests\u25bcReview\u25bcMerge\u25bcDeploy<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<hr\/>\n<h2>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u0432\u0435\u0441\u044c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0432\u0440\u0443\u0447\u043d\u0443\u044e<\/h2>\n<p>\u041f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c \u043a\u0430\u043a \u0434\u043e\u0432\u0435\u0440\u044f\u0442\u044c deployment CI\/CD, \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u043e\u043b\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u043d\u0430 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0439 VM.<\/p>\n<h4>\u041f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/h4>\n<pre><code class=\"bash\">ansible-playbook playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c:<\/p>\n<pre><code class=\"bash\">curl http:\/\/192.168.56.101<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>\u0412\u0442\u043e\u0440\u043e\u0439 \u0437\u0430\u043f\u0443\u0441\u043a<\/h4>\n<pre><code class=\"bash\">ansible-playbook playbooks\/site.yml<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043b\u0438\u0448\u043d\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439.<\/p>\n<h4>Check Mode<\/h4>\n<pre><code class=\"bash\">ansible-playbook \\  playbooks\/site.yml \\  --check \\  --diff<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>Lint<\/h4>\n<pre><code class=\"bash\">ansible-lint .<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>Syntax Check<\/h4>\n<pre><code class=\"bash\">ansible-playbook \\  playbooks\/site.yml \\  --syntax-check<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<h4>Molecule<\/h4>\n<pre><code class=\"bash\">molecule test<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0443\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 GitHub:<\/p>\n<pre><code class=\"bash\">git add .git commit -m \"Add Docker deployment and CI\"git push<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>GitHub Actions \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438.<\/p>\n<hr\/>\n<h2>\u0427\u0442\u043e \u043f\u0440\u043e\u0438\u0437\u043e\u0448\u043b\u043e \u0441 \u0442\u043e\u0447\u043a\u0438 \u0437\u0440\u0435\u043d\u0438\u044f DevOps<\/h2>\n<p>\u0412 \u043d\u0430\u0447\u0430\u043b\u0435 \u0443 \u043d\u0430\u0441 \u0431\u044b\u043b \u0442\u043e\u043b\u044c\u043a\u043e \u0441\u0435\u0440\u0432\u0435\u0440. \u0412\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b:<\/p>\n<pre><code>SSH\u25bcapt update\u25bcDocker\u25bcCompose\u25bcuser\u25bcdirectory\u25bccompose.yml\u25bcdocker compose up<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0451 \u044d\u0442\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e \u043a\u043e\u0434\u043e\u043c. Ansible \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a \u0437\u0430\u0434\u0430\u043d\u043d\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e:<\/p>\n<pre><code>Ubuntu\u251c\u2500\u2500 Docker installed\u251c\u2500\u2500 Docker enabled\u251c\u2500\u2500 deploy exists\u251c\u2500\u2500 \/opt\/myapp exists\u251c\u2500\u2500 compose.yml exists\u2514\u2500\u2500 application running<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0410 CI \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0449\u0451 \u043e\u0434\u0438\u043d \u0443\u0440\u043e\u0432\u0435\u043d\u044c:<\/p>\n<pre><code>Infrastructure as Code\u25bcStatic Analysis\u25bcAutomated Tests\u25bcCode Review\u25bcDeployment<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0418\u043c\u0435\u043d\u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u0437\u0430\u043c\u0435\u0442\u043d\u0430 \u0440\u0430\u0437\u043d\u0438\u0446\u0430 \u043c\u0435\u0436\u0434\u0443 \u043f\u0440\u043e\u0441\u0442\u044b\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c Ansible \u0438 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u043a\u0430\u043a \u043a\u043e\u0434\u043e\u043c.<\/p>\n<hr\/>\n<h2>\u041f\u043e\u0447\u0435\u043c\u0443 \u043c\u044b \u043d\u0435 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Docker \u0447\u0435\u0440\u0435\u0437 Role \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/h2>\n<p>\u041c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043f\u043e\u043c\u0435\u0441\u0442\u0438\u0442\u044c \u0430\u0431\u0441\u043e\u043b\u044e\u0442\u043d\u043e \u0432\u0441\u0451 \u0432 \u043e\u0434\u043d\u0443 Role:<\/p>\n<pre><code>docker_app\u251c\u2500\u2500 Docker\u251c\u2500\u2500 user\u251c\u2500\u2500 directories\u251c\u2500\u2500 Compose\u2514\u2500\u2500 deployment<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0414\u043b\u044f \u0443\u0447\u0435\u0431\u043d\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u044d\u0442\u043e \u0441\u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u0431\u044b. \u041d\u043e \u0442\u0430\u043a\u043e\u0435 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d\u0438\u0435 \u043b\u0443\u0447\u0448\u0435 \u043c\u0430\u0441\u0448\u0442\u0430\u0431\u0438\u0440\u0443\u0435\u0442\u0441\u044f:<\/p>\n<pre><code>Playbook\u2502\u251c\u2500\u2500 Docker host preparation\u2502\u2514\u2500\u2500 docker_app      \u251c\u2500\u2500 user      \u251c\u2500\u2500 directories      \u251c\u2500\u2500 configuration      \u2514\u2500\u2500 deployment<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u041f\u043e\u0437\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0434\u0435\u043b\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 Roles:<\/p>\n<pre><code>roles\/\u251c\u2500\u2500 docker\/\u251c\u2500\u2500 users\/\u251c\u2500\u2500 nginx\/\u2514\u2500\u2500 application\/<\/code><div class=\"code-explainer\"><a href=\"https:\/\/sourcecraft.dev\/\" class=\"tm-button code-explainer__link\" style=\"visibility: hidden;\"><img style=\"width:14px;height:14px;object-fit:cover;object-position:left;\"\/><\/a><\/div><\/pre>\n<p>\u0422\u043e\u0433\u0434\u0430 \u043e\u0434\u043d\u0430 Role \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 Docker, \u0434\u0440\u0443\u0433\u0430\u044f \u2014 \u0437\u0430 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439, \u0442\u0440\u0435\u0442\u044c\u044f \u2014 \u0437\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435.<\/p>\n<hr\/>\n<h2>\u0427\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u0432 production<\/h2>\n<p>\u041d\u0430\u0448 \u043f\u0440\u043e\u0435\u043a\u0442 \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u043e \u043e\u0441\u0442\u0430\u0451\u0442\u0441\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c. \u0414\u043b\u044f production \u0441\u0442\u043e\u0438\u043b\u043e \u0431\u044b:<\/p>\n<ul>\n<li>\n<p>\u0444\u0438\u043a\u0441\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0440\u0441\u0438\u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 inventories \u0434\u043b\u044f \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0439;<\/p>\n<\/li>\n<li>\n<p>\u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0442\u044c \u043f\u0440\u0430\u0432\u0430 CI\/CD;<\/p>\n<\/li>\n<li>\n<p>\u043d\u0435 \u0434\u0430\u0432\u0430\u0442\u044c pipeline \u043d\u0435\u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a production;<\/p>\n<\/li>\n<li>\n<p>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0435\u043a\u0440\u0435\u0442-\u0445\u0440\u0430\u043d\u0438\u043b\u0438\u0449\u0435;<\/p>\n<\/li>\n<li>\n<p>\u043f\u0440\u043e\u0432\u043e\u0434\u0438\u0442\u044c deployment \u0447\u0435\u0440\u0435\u0437 review;<\/p>\n<\/li>\n<li>\n<p>\u0440\u0430\u0437\u0434\u0435\u043b\u044f\u0442\u044c \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u0438 \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e.<\/p>\n<\/li>\n<\/ul>\n<hr\/>\n<h3>\u0420\u0435\u0441\u0443\u0440\u0441\u044b \u0434\u043b\u044f \u043e\u0431\u0443\u0447\u0435\u043d\u0438\u044f<\/h3>\n<h4>1. \u041e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f Ansible<\/h4>\n<p>\u0413\u043b\u0430\u0432\u043d\u044b\u0439 \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a \u0434\u043b\u044f \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u044f Ansible. \u0417\u0434\u0435\u0441\u044c \u0435\u0441\u0442\u044c Getting Started, \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e Playbook, Inventory, Modules, Roles, Variables \u0438 \u0434\u0440\u0443\u0433\u0438\u043c \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0430\u043c. \u0414\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 Ansible \u0438 \u043e\u0442\u043c\u0435\u0447\u0430\u0435\u0442, \u0432 \u043a\u0430\u043a\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043d\u043e\u0432\u044b\u0435 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438. <\/p>\n<p><a href=\"https:\/\/docs.ansible.com\/projects\/ansible\/latest\/index.html\" rel=\"noopener noreferrer nofollow\">Ansible Documentation<\/a><\/p>\n<hr\/>\n<h4>2. Ansible Getting Started<\/h4>\n<p>\u0415\u0441\u043b\u0438 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u0430\u044f \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044f \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u0430\u0447\u0430\u0442\u044c \u043b\u0443\u0447\u0448\u0435 \u0441 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e Quick Start: \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 Ansible \u2192 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u2192 Inventory \u2192 \u043f\u0435\u0440\u0432\u044b\u0439 Playbook. <\/p>\n<p><a href=\"https:\/\/docs.ansible.com\/projects\/ansible\/latest\/getting_started\/get_started_ansible.html\" rel=\"noopener noreferrer nofollow\">Start automating with Ansible<\/a><\/p>\n<hr\/>\n<h4>3. LabEx<\/h4>\n<p>LabEx \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0430\u043a\u0442\u0438\u0432\u043d\u044b\u0435 \u043b\u0430\u0431\u043e\u0440\u0430\u0442\u043e\u0440\u043d\u044b\u0435 \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043f\u043e Ansible, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0443\u0447\u0430\u0442\u044c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0447\u0435\u0440\u0435\u0437 \u0442\u0435\u0440\u043c\u0438\u043d\u0430\u043b \u0431\u0440\u0430\u0443\u0437\u0435\u0440\u0430. \u042d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u043e \u0434\u043b\u044f \u0442\u0435\u0445, \u043a\u0442\u043e \u0445\u043e\u0447\u0435\u0442 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0447\u0438\u0442\u0430\u0442\u044c \u043f\u0440\u043e Inventory, Playbook, Modules \u0438 Roles, \u0430 \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442.<\/p>\n<p><a href=\"https:\/\/labex.io\/learn\/ansible\" rel=\"noopener noreferrer nofollow\">LabEx<\/a><\/p>\n<hr\/>\n<h4>4. Ansible for DevOps \u2014 Jeff Geerling<\/h4>\n<p>\u041e\u0434\u0438\u043d \u0438\u0437 \u043d\u0430\u0438\u0431\u043e\u043b\u0435\u0435 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u0440\u0435\u0441\u0443\u0440\u0441\u043e\u0432 \u0438\u043c\u0435\u043d\u043d\u043e \u0434\u043b\u044f DevOps-\u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438. \u041a\u043d\u0438\u0433\u0430 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0441 \u0431\u0430\u0437\u043e\u0432\u044b\u0445 \u043f\u043e\u043d\u044f\u0442\u0438\u0439, \u0430 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u0445\u043e\u0434\u0438\u0442 \u043a Playbook, \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, Docker \u0438 \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439. \u0410\u0432\u0442\u043e\u0440 \u0440\u0435\u0433\u0443\u043b\u044f\u0440\u043d\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u044f\u0435\u0442 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u0443\u044e \u0432\u0435\u0440\u0441\u0438\u044e; \u0438\u0441\u0445\u043e\u0434\u043d\u044b\u0439 \u0442\u0435\u043a\u0441\u0442 \u043a\u043d\u0438\u0433\u0438 \u0442\u0430\u043a\u0436\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u043e\u0442\u043a\u0440\u044b\u0442\u043e. <\/p>\n<p><a href=\"https:\/\/github.com\/geerlingguy\/ansible-for-devops-manuscript\" rel=\"noopener noreferrer nofollow\">Ansible for DevOps<\/a><\/p>\n<hr\/>\n<h4>5. Ansible Galaxy<\/h4>\n<p>Ansible Galaxy \u2014 User Guide \u2014 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 \u043a\u0430\u0442\u0430\u043b\u043e\u0433, \u0433\u0434\u0435 \u043c\u043e\u0436\u043d\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c, \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c Ansible Roles \u0438 Collections. \u0412 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0435\u0441\u0442\u044c \u043f\u043e\u0438\u0441\u043a \u0440\u043e\u043b\u0435\u0439 \u0438 \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u0439, \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u044b\u0445 \u0432\u0435\u0440\u0441\u0438\u0439, <code>requirements.yml<\/code> \u0438 \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u0435 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u044f\u043c\u0438. <\/p>\n<p><a href=\"https:\/\/docs.ansible.com\/projects\/ansible\/latest\/galaxy\/user_guide.html\" rel=\"noopener noreferrer nofollow\">Ansible Galaxy <\/a><\/p>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0441\u0442\u043e\u0438\u0442 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c <a href=\"https:\/\/docs.ansible.com\/projects\/ansible\/latest\/galaxy\/dev_guide.html\" rel=\"noopener noreferrer nofollow\">Ansible Galaxy Developer Guide<\/a>, \u0435\u0441\u043b\u0438 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0438 \u043f\u0443\u0431\u043b\u0438\u043a\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0435 Roles \u0438\u043b\u0438 Collections. <\/p>\n<hr\/>\n<h4>6. ansible-lint<\/h4>\n<p>Ansible Lint \u2014 \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0430\u043d\u0430\u043b\u0438\u0437\u0430\u0442\u043e\u0440 \u0434\u043b\u044f Ansible Playbooks, Roles \u0438 Collections. \u041e\u043d \u043f\u043e\u043c\u043e\u0433\u0430\u0435\u0442 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u044c \u0440\u0430\u0441\u043f\u0440\u043e\u0441\u0442\u0440\u0430\u043d\u0451\u043d\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u0441\u043e\u0431\u043b\u044e\u0434\u0430\u0442\u044c \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u043c\u044b\u0435 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u0438 \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0435\u0434\u0438\u043d\u044b\u0439 \u0441\u0442\u0438\u043b\u044c \u043a\u043e\u0434\u0430. <\/p>\n<p><a href=\"https:\/\/docs.ansible.com\/projects\/lint\/\" rel=\"noopener noreferrer nofollow\">Ansible Lint<\/a><\/p>\n<hr\/>\n<h4>7. Molecule<\/h4>\n<p>Molecule \u2014 \u0444\u0440\u0435\u0439\u043c\u0432\u043e\u0440\u043a \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Ansible Roles, Playbooks \u0438 Collections. \u041e\u043d \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0442\u0435\u0441\u0442\u043e\u0432\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u044e \u043d\u0430 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430\u0445, \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0445 \u043c\u0430\u0448\u0438\u043d\u0430\u0445 \u0438 \u0434\u0440\u0443\u0433\u0438\u0445 \u0441\u0438\u0441\u0442\u0435\u043c\u0430\u0445, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 Ansible.<\/p>\n<p><a href=\"https:\/\/github.com\/ansible\/molecule?\" rel=\"noopener noreferrer nofollow\">Molecule<\/a> <\/p>\n<hr\/>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>Ansible \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0430\u0436\u043d\u043e\u0435 \u043c\u0435\u0441\u0442\u043e \u043c\u0435\u0436\u0434\u0443 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u043e\u0439 \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435\u043c. \u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0438\u0434\u0435\u044f, \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0441\u0442\u043e\u0438\u0442 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u0438\u0437 \u044d\u0442\u043e\u0433\u043e \u0431\u043b\u043e\u043a\u0430: <strong>DevOps \u2014 \u044d\u0442\u043e \u043d\u0435 \u043d\u0430\u0431\u043e\u0440 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432, \u0430 \u0441\u043f\u043e\u0441\u043e\u0431 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0432\u0435\u0441\u044c \u0436\u0438\u0437\u043d\u0435\u043d\u043d\u044b\u0439 \u0446\u0438\u043a\u043b \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/strong>. Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443, Ansible \u043f\u0440\u0438\u0432\u043e\u0434\u0438\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u044b \u043a \u043d\u0443\u0436\u043d\u043e\u043c\u0443 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044e, Docker \u0438 Kubernetes \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u044e\u0442 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u0430 CI\/CD \u0441\u0432\u044f\u0437\u044b\u0432\u0430\u0435\u0442 \u044d\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u044b \u0438 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0438\u0445 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438.<\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u0431\u0430\u0437\u043e\u0432\u044b\u0439 \u0431\u043b\u043e\u043a Ansible \u0437\u0430\u043a\u0430\u043d\u0447\u0438\u0432\u0430\u0435\u0442\u0441\u044f. \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0448\u0430\u0433 \u2014 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043e\u0442 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u043e\u0432 \u043a <strong>\u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0443 \u0438 \u043d\u0430\u0431\u043b\u044e\u0434\u0430\u0435\u043c\u043e\u0441\u0442\u0438 (Observability)<\/strong>: Prometheus, Grafana, Loki, \u0441\u0431\u043e\u0440 \u043c\u0435\u0442\u0440\u0438\u043a \u0438 \u043b\u043e\u0433\u043e\u0432, \u0438 \u0442.\u0434., \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b.<\/p>\n<\/div>\n<p>\u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/1071014\/\">https:\/\/habr.com\/ru\/articles\/1071014\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u0412 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u0442\u0430\u0442\u044c\u044f\u0445 \u043c\u044b \u043f\u043e\u0437\u043d\u0430\u043a\u043e\u043c\u0438\u043b\u0438\u0441\u044c \u0441 \u043e\u0441\u043d\u043e\u0432\u0430\u043c\u0438 Ansible, \u0441\u043e\u0437\u0434\u0430\u043b\u0438 Inventory, \u043d\u0430\u043f\u0438\u0441\u0430\u043b\u0438 \u043f\u0435\u0440\u0432\u044b\u0435 Playbook \u0438 \u043d\u0430\u0443\u0447\u0438\u043b\u0438\u0441\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Roles, Templates, Variables \u0438 Ansible Vault. \u0422\u0435\u043f\u0435\u0440\u044c \u043f\u0440\u0438\u0448\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u043d\u0430 Ansible \u0441 \u0434\u0440\u0443\u0433\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b.\u0412  \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430\u0445 Ansible \u0440\u0435\u0434\u043a\u043e \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e. \u041e\u043d \u043c\u043e\u0436\u0435\u0442 \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0432\u043c\u0435\u0441\u0442\u0435 \u0441 Terraform, Docker, Kubernetes, GitHub Actions, GitLab CI \u0438\u043b\u0438 Jenkins.\u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u044b\u0435 \u043c\u0430\u0448\u0438\u043d\u044b \u0438 \u0441\u0435\u0442\u0438, Ansible \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u043d\u0430 \u043d\u0438\u0445 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0435 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e\u0435 \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435, Docker \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0442 \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u044b, \u0430 CI\/CD \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u0432\u0435\u0441\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u043e\u0441\u043b\u0435 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043a\u043e\u0434\u0430. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u0431\u044a\u0435\u0434\u0438\u043d\u0438\u043c \u0438\u0437\u0443\u0447\u0435\u043d\u043d\u044b\u0435 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u0432 \u0435\u0434\u0438\u043d\u0443\u044e \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u0438 \u0440\u0430\u0437\u0431\u0435\u0440\u0451\u043c, \u0433\u0434\u0435 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f Ansible \u0432 \u0441\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 DevOps-\u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435.Terraform + Ansible: \u0434\u0432\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u2014 \u0434\u0432\u0435 \u0437\u0430\u0434\u0430\u0447\u0438Terraform\u25bc\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b\u251c\u2500\u2500 Network\u251c\u2500\u2500 Virtual Machine\u251c\u2500\u2500 Disk\u2514\u2500\u2500 Load Balancer\u2502\u25bcAnsible\u251c\u2500\u2500 Users\u251c\u2500\u2500 Packages\u251c\u2500\u2500 Docker\u251c\u2500\u2500 Nginx\u251c\u2500\u2500 Configuration\u2514\u2500\u2500 ApplicationTerraform \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u043f\u0440\u0435\u0438\u043c\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0437\u0430 Infrastructure as Code, \u0430 Ansible \u2014 \u0437\u0430 Configuration Management. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u043c\u043e\u0436\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443:resource &#171;&#8230;&#187; &#171;web&#187; {  # \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0439 \u043c\u0430\u0448\u0438\u043d\u044b}\u041f\u043e\u0441\u043b\u0435 \u0435\u0451 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f Ansible \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Docker:- name: Install Docker  hosts: web  become: true  tasks:    &#8212; name: Install Docker      ansible.builtin.apt:        name: docker.io        state: present\u041f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u044c:Terraform \u2192 Infrastructure \u2192 Ansible \u2192 ConfigurationTerraform \u2192 Ansible\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430\u043c\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, Terraform \u0441\u043e\u0437\u0434\u0430\u043b:web-01 \u2192 10.10.1.10web-02 \u2192 10.10.1.11web-03 \u2192 10.10.1.12Ansible \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u044d\u0442\u0438 \u0430\u0434\u0440\u0435\u0441\u0430 \u0438 \u043f\u043e\u043d\u044f\u0442\u044c, \u043a \u043a\u0430\u043a\u0438\u043c \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c\u0441\u044f. \u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432 \u043c\u043e\u0436\u043d\u043e \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043e\u0431\u044b\u0447\u043d\u044b\u0439 Inventory \u0432\u0440\u0443\u0447\u043d\u0443\u044e. \u041e\u0434\u043d\u0430\u043a\u043e \u0432 \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u0431\u044b\u0441\u0442\u0440\u043e \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u0441\u044f \u043d\u0435\u0443\u0434\u043e\u0431\u043d\u044b\u043c. \u0415\u0441\u043b\u0438 Terraform \u043a\u0430\u0436\u0434\u044b\u0439 \u0434\u0435\u043d\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0438 \u0443\u0434\u0430\u043b\u044f\u0435\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u044b, \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a IP-\u0430\u0434\u0440\u0435\u0441\u043e\u0432 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u043f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043d\u0435\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e. \u0417\u0434\u0435\u0441\u044c \u043f\u043e\u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f Dynamic Inventory.Dynamic Inventory\u041e\u0431\u044b\u0447\u043d\u044b\u0439 Inventory \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:[web]10.10.1.1010.10.1.11[database]10.10.2.10\u041d\u043e \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043c\u043e\u0436\u0435\u0442 \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c\u0441\u044f:10.10.1.10 \u2192 \u0443\u0434\u0430\u043b\u0451\u043d10.10.1.11 \u2192 \u0443\u0434\u0430\u043b\u0451\u043d10.10.1.20 \u2192 \u0441\u043e\u0437\u0434\u0430\u043d10.10.1.21 \u2192 \u0441\u043e\u0437\u0434\u0430\u043d\u0415\u0441\u043b\u0438 Inventory \u043d\u0435 \u043e\u0431\u043d\u043e\u0432\u0438\u0442\u044c, Ansible \u0431\u0443\u0434\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e. Dynamic Inventory \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u043e\u043b\u0443\u0447\u0430\u0442\u044c \u0441\u043f\u0438\u0441\u043e\u043a \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u043d\u0435\u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u0438\u0437 \u0432\u043d\u0435\u0448\u043d\u0435\u0433\u043e \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:Cloud Provider\u25bcDynamic Inventory\u25bcAnsible\u0412 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0431\u044b\u0442\u044c:AWS;Azure;Google Cloud;Kubernetes;VMware;\u0434\u0440\u0443\u0433\u0438\u0435 \u0441\u0438\u0441\u0442\u0435\u043c\u044b.\u042d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e \u043f\u043e\u043b\u0435\u0437\u043d\u043e \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438 \u043f\u043e\u0441\u0442\u043e\u044f\u043d\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u044f\u044e\u0449\u0438\u0445\u0441\u044f \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445.Provisioners: \u043f\u043e\u0447\u0435\u043c\u0443 \u0438\u0445 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442 \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u043eTerraform \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c Provisioners, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043a\u043e\u043c\u0430\u043d\u0434\u044b \u043f\u043e\u0441\u043b\u0435 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0440\u0435\u0441\u0443\u0440\u0441\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:provisioner &#171;remote-exec&#187; {  inline = [    &#171;sudo apt update&#187;,    &#171;sudo apt install nginx -y&#187;  ]}\u041d\u0430 \u043f\u0435\u0440\u0432\u044b\u0439 \u0432\u0437\u0433\u043b\u044f\u0434 \u044d\u0442\u043e \u0443\u0434\u043e\u0431\u043d\u043e: Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0435\u0440\u0432\u0435\u0440 \u0438 \u0441\u0440\u0430\u0437\u0443 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043a\u043e\u043c\u0430\u043d\u0434\u044b. \u041d\u043e \u0434\u043b\u044f \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432 \u0442\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043e\u0431\u044b\u0447\u043d\u043e \u043d\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043b\u0443\u0447\u0448\u0438\u043c \u0440\u0435\u0448\u0435\u043d\u0438\u0435\u043c. Provisioners:\u0441\u043b\u043e\u0436\u043d\u0435\u0435 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c;\u0445\u0443\u0436\u0435 \u0438\u043d\u0442\u0435\u0433\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u044b\u043c \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u0435\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438;\u043c\u043e\u0433\u0443\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0430\u0437\u0432\u0451\u0440\u0442\u044b\u0432\u0430\u043d\u0438\u044f \u043c\u0435\u043d\u0435\u0435 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u044b\u043c;\u0441\u043c\u0435\u0448\u0438\u0432\u0430\u044e\u0442 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u044b \u0438 \u0435\u0451 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0443.Provisioners \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u043e\u0433\u0443\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0434\u043b\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u043d\u043e \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u044b \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u0438 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u0432.Terraform \u2192 Ansible\u041d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0435\u0440\u0435\u0434\u0430\u0442\u044c \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e \u043e\u0442 Terraform \u043a Ansible. \u0421\u0430\u043c\u044b\u0439 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 Terraform \u0441\u043e\u0437\u0434\u0430\u0451\u0442 \u0441\u0435\u0440\u0432\u0435\u0440, \u0430 \u0435\u0433\u043e IP-\u0430\u0434\u0440\u0435\u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0432 Inventory. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440:Terraform\u25bc192.168.56.101\u25bcAnsible Inventory\u25bcAnsible Playbook\u0414\u043b\u044f \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 Inventory:all:  children:    web:      hosts:        web-01:          ansible_host:          192.168.56.101\u0412 \u0431\u043e\u043b\u044c\u0448\u0438\u0445 \u0438\u043d\u0444\u0440\u0430\u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430\u0445 \u0443\u0434\u043e\u0431\u043d\u0435\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Dynamic Inventory.\u041f\u0440\u0430\u043a\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u043e\u0435\u043a\u0442: Ansible + Docker Compose + Molecule + CI\/CD\u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0432\u0441\u0451 \u0438\u0437\u0443\u0447\u0435\u043d\u043d\u043e\u0435 \u0432 \u043e\u0434\u0438\u043d \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439, \u043d\u043e \u0443\u0436\u0435 \u043f\u0440\u0438\u0431\u043b\u0438\u0436\u0435\u043d\u043d\u044b\u0439 \u043a \u0440\u0435\u0430\u043b\u044c\u043d\u043e\u043c\u0443 \u043f\u0440\u043e\u0435\u043a\u0442. \u041d\u0430\u0448\u0430 \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u043c\u0430\u043d\u0434 \u043d\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435, \u0430 \u043f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0432\u043e\u0441\u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u0438\u043c\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441:Developer\u25bcGit\u25bcGitHub Actions\u251c\u2500\u2500 ansible-lint\u251c\u2500\u2500 syntax check\u2514\u2500\u2500 Molecule       \u25bc  Ansible Role       \u25bc Ubuntu Server       \u2502        \u251c\u2500\u2500 Docker Engine       \u251c\u2500\u2500 Docker Compose v2       \u251c\u2500\u2500 deploy       \u2502       \u2514\u2500\u2500 \/opt\/myapp            \u2502            \u2514\u2500\u2500 Docker Compose            \u251c\u2500\u2500 Nginx            \u251c\u2500\u2500 Redis            \u2514\u2500\u2500 PostgreSQL\u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e:\u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0447\u0435\u0440\u0435\u0437 Ansible;\u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u0431\u0435\u0437 \u043b\u0438\u0448\u043d\u0438\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439;\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c &#8212;check;\u043f\u0440\u043e\u0432\u0435\u0440\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 ansible-lint;\u043f\u0440\u043e\u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u043b\u044c \u0447\u0435\u0440\u0435\u0437 Molecule;\u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0447\u0435\u0440\u0435\u0437 GitHub Actions.\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u044b \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u043b\u0438 \u0438 \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0439 \u0434\u0435\u043f\u043b\u043e\u0439. Molecule \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u043e\u043b\u0438 \u0432 \u0438\u0437\u043e\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u043c Docker-\u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438, \u0430 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u044b\u0439 Docker Compose deployment \u2014 \u043d\u0430 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0439 Ubuntu-\u043c\u0430\u0448\u0438\u043d\u0435. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043d\u0435 \u043f\u044b\u0442\u0430\u0442\u044c\u0441\u044f \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c Docker daemon \u0432\u043d\u0443\u0442\u0440\u0438 \u0442\u0435\u0441\u0442\u043e\u0432\u043e\u0433\u043e \u043a\u043e\u043d\u0442\u0435\u0439\u043d\u0435\u0440\u0430.\u0427\u0442\u043e \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f\u0414\u043b\u044f \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f:Control Node \u0441 Linux;Ansible;Git;Docker \u043d\u0430 Control Node \u2014 \u043e\u043d \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f Molecule;Ubuntu Managed Node;SSH-\u0434\u043e\u0441\u0442\u0443\u043f \u043a Managed Node;GitHub-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439.\u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 Managed Node \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u0437\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0441\u0435\u0440\u0432\u0435\u0440, \u043e\u0431\u043b\u0430\u0447\u043d\u0443\u044e VM \u0438\u043b\u0438 \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u0443\u044e \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u0443\u044e \u043c\u0430\u0448\u0438\u043d\u0443 VirtualBox.\u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u043e\u0436\u0438\u043c:Control Node192.168.56.1Managed Node192.168.56.101IP-\u0430\u0434\u0440\u0435\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430 \u0441\u0432\u043e\u0438.\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u0430\u0442\u0430\u043b\u043e\u0433:mkdir ansible-docker-democd ansible-docker-demo\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0431\u0430\u0437\u043e\u0432\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:ansible-docker-demo\/\u251c\u2500\u2500 ansible.cfg\u251c\u2500\u2500 requirements.yml\u251c\u2500\u2500 inventory\/\u2502   \u2514\u2500\u2500 hosts.yml\u251c\u2500\u2500 playbooks\/\u2502   \u2514\u2500\u2500 site.yml\u251c\u2500\u2500 roles\/\u2502   \u2514\u2500\u2500 docker_app\/\u2502       \u251c\u2500\u2500 defaults\/\u2502       \u2502   \u2514\u2500\u2500 main.yml\u2502       \u251c\u2500\u2500 handlers\/\u2502       \u2502   \u2514\u2500\u2500 main.yml\u2502       \u251c\u2500\u2500 tasks\/\u2502       \u2502   \u251c\u2500\u2500 main.yml\u2502       \u2502   \u2514\u2500\u2500 deploy.yml\u2502       \u251c\u2500\u2500 templates\/\u2502       \u2502   \u2514\u2500\u2500 compose.yml.j2\u2502       \u2514\u2500\u2500 meta\/\u2502           \u2514\u2500\u2500 main.yml\u251c\u2500\u2500 molecule\/\u2502   \u2514\u2500\u2500 docker_app\/\u2502       \u251c\u2500\u2500 converge.yml\u2502       \u251c\u2500\u2500 molecule.yml\u2502       \u2514\u2500\u2500 verify.yml\u2514\u2500\u2500 .github\/    \u2514\u2500\u2500 workflows\/      \u2514\u2500\u2500 ansible.yml\u0417\u0434\u0435\u0441\u044c \u0432\u043f\u0435\u0440\u0432\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u0443\u044e Role.Ansible Role \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0432\u044b\u043d\u0435\u0441\u0442\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u044f\u0435\u043c\u0443\u044e \u043a\u043e\u043d\u0444\u0438\u0433\u0443\u0440\u0430\u0446\u0438\u044e \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u0430\u0442\u0430\u043b\u043e\u0433\u043e\u0432 \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0430\u0442\u044c \u0435\u0451 \u0438\u0437 \u0440\u0430\u0437\u043d\u044b\u0445 Playbook. Ansible \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Roles \u0434\u043b\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u0435\u0440\u0435\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u043e\u0439 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0437\u0430\u0446\u0438\u0438.\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438\u041d\u0430 Control Node \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0435 Python:python3 -m venv .venvsource .venv\/bin\/activate\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b:pip install \\  ansible-core \\  ansible-lint \\  molecule \\  molecule-plugins[docker]ansible-lint \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u043b\u044f \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u043e\u0433\u043e \u0430\u043d\u0430\u043b\u0438\u0437\u0430 Ansible-\u043a\u043e\u0434\u0430, \u0430 Molecule \u2014 \u0434\u043b\u044f \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f Roles \u0438 Playbook. Ansible \u043e\u0442\u043d\u043e\u0441\u0438\u0442 \u043e\u0431\u0430 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u0430 \u043a \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u043c \u0441\u0440\u0435\u0434\u0441\u0442\u0432\u0430\u043c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 Ansible-\u043a\u043e\u0434\u0430. \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c requirements.yml:&#8212;collections:  &#8212; name: community.docker\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c \u043a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044e:ansible-galaxy collection install -r requirements.yml\u041a\u043e\u043b\u043b\u0435\u043a\u0446\u0438\u044f community.docker \u043d\u0435 \u0432\u0445\u043e\u0434\u0438\u0442 \u0432 ansible-core. \u041e\u043d\u0430 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442\u0441\u044f \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0438 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, community.docker.docker_compose_v2.\u041d\u0430\u0441\u0442\u0440\u0430\u0438\u0432\u0430\u0435\u043c Ansible\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c ansible.cfg:[defaults]inventory = inventory\/hosts.ymlroles_path = roleshost_key_checking = Falseinterpreter_python = auto_silent\u041f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 roles_path \u0433\u043e\u0432\u043e\u0440\u0438\u0442 Ansible, \u0433\u0434\u0435 \u0438\u0441\u043a\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0435 Roles. \u0422\u0435\u043f\u0435\u0440\u044c Inventory.inventory\/hosts.yml&#8212;all:  children:    web:      hosts:        web-01:          ansible_host: 192.168.56.101          ansible_user: ubuntu\u041f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443:ansible-inventory &#8212;graph\u041f\u043e\u043b\u0443\u0447\u0438\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e:@all:  |&#8212;@ungrouped:  |&#8212;@web:  |    |&#8212;web-01\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c SSH\u0414\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430 Playbook \u0441\u043d\u0430\u0447\u0430\u043b\u0430 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u043e\u0431\u044b\u0447\u043d\u043e\u0435 SSH-\u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435:ssh ubuntu@192.168.56.101\u0415\u0441\u043b\u0438 \u043e\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442, \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c Ansible:ansible web -m ansible.builtin.ping\u0420\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442:web-01 | SUCCESS =&gt; {    &#171;changed&#187;: false,    &#171;ping&#187;: &#171;pong&#187;}\u0417\u0434\u0435\u0441\u044c ping \u2014 \u043d\u0435 ICMP ping. \u041c\u043e\u0434\u0443\u043b\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u0442, \u0441\u043f\u043e\u0441\u043e\u0431\u0435\u043d \u043b\u0438 Ansible \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0442\u044c\u0441\u044f \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0438\u0442\u044c \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435.\u0423\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u043c Docker Engine \u0438 Compose v2\u0422\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0434\u0433\u043e\u0442\u043e\u0432\u0438\u043c Managed Node. Docker \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0442\u044c Docker Engine \u043d\u0430 Ubuntu \u0447\u0435\u0440\u0435\u0437 \u043e\u0444\u0438\u0446\u0438\u0430\u043b\u044c\u043d\u044b\u0439 APT-\u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439. \u0412 \u0441\u043e\u0441\u0442\u0430\u0432 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 \u0432\u0445\u043e\u0434\u044f\u0442 Docker Engine, Docker CLI, containerd.io, Buildx \u0438 Docker Compose plugin. \u0412\u0430\u0436\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442: \u043d\u0435 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Ubuntu-\u043f\u0430\u043a\u0435\u0442 docker.io \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043d\u0430\u0434\u0435\u044f\u0442\u044c\u0441\u044f \u043d\u0430 \u043d\u0430\u043b\u0438\u0447\u0438\u0435 Compose.\u041d\u0430\u043c \u043d\u0443\u0436\u043d\u044b:docker-cedocker-ce-clicontainerd.iodocker-buildx-plugindocker-compose-plugin\u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c playbooks\/site.yml:&#8212;- name: Prepare Docker host  hosts: web  become: true  tasks:    &#8212; name: Install prerequisites      ansible.builtin.apt:        name:          &#8212; ca-certificates          &#8212; curl        state: present        update_cache: true    &#8212; name: Create Docker keyrings directory      ansible.builtin.file:        path: \/etc\/apt\/keyrings        state: directory        mode: &#171;0755&#187;    &#8212; name: Download Docker GPG key      ansible.builtin.get_url:        url: https:\/\/download.docker.com\/linux\/ubuntu\/gpg        dest: \/etc\/apt\/keyrings\/docker.asc        mode: &#171;0644&#187;    &#8212; name: Configure Docker repository      ansible.builtin.copy:        dest: \/etc\/apt\/sources.list.d\/docker.sources        mode: &#171;0644&#187;        content: |          Types: deb          URIs: https:\/\/download.docker.com\/linux\/ubuntu          Suites: {{ ansible_facts.distribution_release }}          Components: stable          Architectures: {{ ansible_facts.architecture }}          Signed-By: \/etc\/apt\/keyrings\/docker.asc    &#8212; name: Install Docker      ansible.builtin.apt:        name:          &#8212; docker-ce          &#8212; docker-ce-cli          &#8212; containerd.io          &#8212; docker-buildx-plugin          &#8212; docker-compose-plugin        state: present        update_cache: true    &#8212; name: Start Docker      ansible.builtin.systemd:        name: docker        state: started        enabled: true\u0417\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c:ansible-playbook playbooks\/site.yml\u041f\u0440\u043e\u0432\u0435\u0440\u044f\u0435\u043c Docker:ansible web \\  -m ansible.builtin.command \\  -a &#171;docker &#8212;version&#187;\u0418 Compose:ansible web \\  -m ansible.builtin.command \\  -a &#171;docker compose version&#187;Docker Compose v2 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-491095","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/491095","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=491095"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/491095\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=491095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=491095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=491095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}