Những điều cơ bản về Ansible, nếu không có nó thì vở kịch của bạn sẽ chỉ là một cục mì dính

Tôi đánh giá rất nhiều mã Ansible của người khác và bản thân tôi cũng viết rất nhiều. Trong quá trình phân tích những sai lầm (của cả người khác và của chính tôi), cũng như một số cuộc phỏng vấn, tôi nhận ra sai lầm chính mà người dùng Ansible mắc phải - họ đi vào những thứ phức tạp mà không nắm vững những điều cơ bản.

Để khắc phục sự bất công phổ biến này, tôi quyết định viết bài giới thiệu về Ansible cho những ai đã biết về nó. Tôi cảnh báo bạn, đây không phải là câu chuyện kể lại của con người, đây là một câu chuyện dài với rất nhiều chữ cái và không có hình ảnh.

Mức độ mong đợi của người đọc là hàng nghìn dòng yamla đã được viết sẵn, một số thứ đã được sản xuất nhưng “không hiểu sao mọi thứ đều quanh co”.

Tiêu đề

Sai lầm chính mà người dùng Ansible mắc phải là không biết thứ gì đó được gọi là gì. Nếu bạn không biết tên, bạn không thể hiểu tài liệu nói gì. Một ví dụ sống động: trong một cuộc phỏng vấn, một người dường như nói rằng anh ấy đã viết rất nhiều bằng Ansible không thể trả lời câu hỏi “một playbook bao gồm những yếu tố nào?” Và khi tôi gợi ý rằng “câu trả lời được mong đợi là vở kịch bao gồm trò chơi”, thì nhận xét đáng nguyền rủa “chúng tôi không sử dụng cái đó” theo sau. Mọi người viết Ansible để kiếm tiền và không sử dụng trò chơi. Họ thực sự sử dụng nó, nhưng không biết nó là gì.

Vì vậy, hãy bắt đầu với một điều đơn giản: nó được gọi là gì? Có thể bạn biết điều này, hoặc có thể không, vì bạn đã không chú ý khi đọc tài liệu.

ansible-playbook thực thi playbook. Playbook là một tệp có phần mở rộng yml/yaml, bên trong có nội dung như thế này:

---
- hosts: group1
  roles:
    - role1

- hosts: group2,group3
  tasks:
    - debug:

Chúng tôi đã nhận ra rằng toàn bộ tập tin này là một cẩm nang. Chúng tôi có thể chỉ ra vai trò ở đâu và nhiệm vụ ở đâu. Nhưng chơi ở đâu? Và sự khác biệt giữa trò chơi và vai trò hay sách vở là gì?

Đó là tất cả trong tài liệu. Và họ nhớ nó. Người mới bắt đầu - vì có quá nhiều thứ và bạn sẽ không nhớ được mọi thứ cùng một lúc. Có kinh nghiệm - bởi vì “những điều tầm thường”. Nếu bạn có kinh nghiệm, hãy đọc lại các trang này ít nhất sáu tháng một lần và mã của bạn sẽ trở thành hàng đầu.

Vì vậy, hãy nhớ: Playbook là một danh sách bao gồm các trò chơi và import_playbook.
Đây là một vở kịch:

- hosts: group1
  roles:
    - role1

và đây cũng là một vở kịch khác:

- hosts: group2,group3
  tasks:
    - debug:

Chơi là gì? Tại sao lại là cô ấy?

Chơi là một thành phần quan trọng của sổ chơi, vì chơi và chỉ chơi liên kết danh sách các vai trò và/hoặc nhiệm vụ với danh sách máy chủ mà chúng phải được thực thi trên đó. Trong chiều sâu của tài liệu bạn có thể tìm thấy đề cập đến delegate_to, plugin tra cứu cục bộ, cài đặt dành riêng cho mạng, máy chủ nhảy, v.v. Chúng cho phép bạn thay đổi một chút nơi thực hiện nhiệm vụ. Nhưng, hãy quên nó đi. Mỗi tùy chọn thông minh này đều có những cách sử dụng rất cụ thể và chắc chắn chúng không phổ biến. Và chúng ta đang nói về những điều cơ bản mà mọi người nên biết và sử dụng.

Nếu bạn muốn biểu diễn “cái gì đó” “ở đâu đó”, bạn viết play. Không phải là một vai trò. Không phải là một vai trò với các mô-đun và đại biểu. Bạn lấy nó và viết chơi. Trong đó, trong trường máy chủ, bạn liệt kê nơi thực thi và trong vai trò/nhiệm vụ - những gì cần thực thi.

Đơn giản phải không? Làm sao có thể khác được?

Một trong những khoảnh khắc đặc trưng khi mọi người mong muốn thực hiện điều này không thông qua vui chơi là “vai trò sắp đặt mọi thứ”. Tôi muốn có một vai trò định cấu hình cả máy chủ thuộc loại thứ nhất và máy chủ thuộc loại thứ hai.

Một ví dụ nguyên mẫu là giám sát. Tôi muốn có một vai trò giám sát sẽ cấu hình giám sát. Vai trò giám sát được giao cho các máy chủ giám sát (theo lối chơi). Nhưng hóa ra để theo dõi, chúng tôi cần phân phối các gói hàng đến máy chủ mà chúng tôi đang theo dõi. Tại sao không sử dụng đại biểu? Bạn cũng cần cấu hình iptables. đại biểu? Bạn cũng cần viết/sửa cấu hình cho DBMS để kích hoạt tính năng giám sát. đại biểu! Và nếu thiếu tính sáng tạo thì bạn có thể ủy quyền include_role trong một vòng lặp lồng nhau bằng cách sử dụng bộ lọc phức tạp trên danh sách các nhóm và bên trong include_role bạn có thể làm nhiều hơn nữa delegate_to lại. Và chúng ta đi tiếp...

Một mong muốn tốt - có một vai trò giám sát duy nhất, "làm mọi thứ" - dẫn chúng ta vào địa ngục hoàn toàn mà từ đó thường chỉ có một lối thoát: viết lại mọi thứ từ đầu.

Sai lầm xảy ra ở đâu ở đây? Thời điểm bạn phát hiện ra rằng để thực hiện nhiệm vụ "x" trên máy chủ X, bạn phải đến máy chủ Y và thực hiện "y" ở đó, bạn phải thực hiện một bài tập đơn giản: đi và viết play, điều này trên máy chủ Y thực hiện y. Đừng thêm nội dung nào đó vào "x" mà hãy viết lại từ đầu. Ngay cả với các biến được mã hóa cứng.

Có vẻ như mọi thứ trong đoạn văn trên đều được nói chính xác. Nhưng đây không phải là trường hợp của bạn! Bởi vì bạn muốn viết mã có thể sử dụng lại DRY và giống như thư viện, và bạn cần tìm kiếm một phương pháp để thực hiện điều đó.

Đây là nơi ẩn giấu một sai lầm nghiêm trọng khác. Một lỗi đã biến nhiều dự án từ chỗ được viết ở mức chấp nhận được (có thể tốt hơn, nhưng mọi thứ đều hoạt động tốt và dễ dàng hoàn thành) trở thành một nỗi kinh hoàng hoàn toàn mà ngay cả tác giả cũng không thể hiểu được. Nó hoạt động, nhưng Chúa cấm bạn thay đổi bất cứ điều gì.

Lỗi là: vai trò là một chức năng thư viện. Sự tương tự này đã phá hỏng rất nhiều khởi đầu tốt đẹp đến nỗi thật buồn khi xem. Vai trò này không phải là một chức năng thư viện. Cô ấy không thể tính toán và không thể đưa ra quyết định ở cấp độ chơi. Nhắc nhở tôi những quyết định mà trò chơi đưa ra?

Cảm ơn, bạn nói đúng. Play đưa ra quyết định (chính xác hơn là nó chứa thông tin) về nhiệm vụ và vai trò nào cần thực hiện trên máy chủ nào.

Nếu bạn ủy quyền quyết định này cho một vai trò và thậm chí với các tính toán, bạn sẽ tự kết liễu mình (và người sẽ cố gắng phân tích mã của bạn) phải sống khốn khổ. Vai trò không quyết định nó được thực hiện ở đâu. Quyết định này được thực hiện bằng cách chơi. Vai trò thực hiện những gì nó được bảo, ở nơi nó được bảo.

Tại sao lập trình trong Ansible lại nguy hiểm và tại sao COBOL tốt hơn Ansible, chúng ta sẽ nói trong chương về các biến và jinja. Bây giờ, hãy nói một điều - mỗi phép tính của bạn đều để lại dấu vết không thể xóa nhòa về những thay đổi trong các biến toàn cục và bạn không thể làm bất cứ điều gì về điều đó. Ngay khi hai “dấu vết” giao nhau, mọi thứ đã biến mất.

Lưu ý dành cho người khó tính: vai trò này chắc chắn có thể ảnh hưởng đến luồng điều khiển. Ăn delegate_to và nó có công dụng hợp lý. Ăn meta: end host/play. Nhưng! Hãy nhớ rằng chúng tôi dạy những điều cơ bản? Quên mất delegate_to. Chúng ta đang nói về mã Ansible đơn giản và đẹp nhất. Nó dễ đọc, dễ viết, dễ gỡ lỗi, dễ kiểm tra và dễ hoàn thành. Vì vậy, một lần nữa:

play và only play quyết định máy chủ nào sẽ thực hiện những gì.

Trong phần này, chúng ta đề cập đến sự đối lập giữa trò chơi và vai trò. Bây giờ hãy nói về mối quan hệ giữa nhiệm vụ và vai trò.

Nhiệm vụ và vai trò

Cân nhắc việc chơi:

- hosts: somegroup
  pre_tasks:
    - some_tasks1:
  roles:
     - role1
     - role2
  post_tasks:
     - some_task2:
     - some_task3:

Giả sử bạn cần thực hiện foo. Và có vẻ như foo: name=foobar state=present. Tôi nên viết cái này ở đâu? trước? bưu kiện? Tạo một vai trò?

...Và nhiệm vụ đã đi đâu?

Chúng ta lại bắt đầu với những điều cơ bản - thiết bị chơi. Nếu bạn lơ là về vấn đề này, bạn không thể lấy trò chơi làm cơ sở cho mọi thứ khác và kết quả của bạn sẽ là "không ổn định".

Thiết bị phát: chỉ thị máy chủ, cài đặt cho chính trò chơi và các phần pre_task, nhiệm vụ, vai trò, post_tasks. Các thông số còn lại để chơi bây giờ không còn quan trọng đối với chúng tôi.

Thứ tự các phần của họ với nhiệm vụ và vai trò: pre_tasks, roles, tasks, post_tasks. Vì về mặt ngữ nghĩa, thứ tự thực hiện nằm giữa tasks и roles không rõ ràng thì các phương pháp hay nhất cho thấy rằng chúng tôi đang thêm một phần tasks, chỉ nếu không roles... Nếu đó là roles, sau đó tất cả các tác vụ đính kèm sẽ được đặt trong các phần pre_tasks/post_tasks.

Tất cả những gì còn lại là mọi thứ đều rõ ràng về mặt ngữ nghĩa: đầu tiên pre_tasks, sau đó roles, sau đó post_tasks.

Nhưng chúng ta vẫn chưa trả lời được câu hỏi: lệnh gọi mô-đun ở đâu? foo viết? Chúng ta có cần viết toàn bộ vai trò cho mỗi mô-đun không? Hay tốt hơn là nên có một vai trò dày đặc cho mọi việc? Và nếu không phải là một vai trò thì tôi nên viết ở đâu - trước hay sau?

Nếu không có câu trả lời hợp lý cho những câu hỏi này, thì đây là dấu hiệu của sự thiếu trực giác, tức là những “nền tảng lung lay” tương tự. Hãy tìm ra nó. Đầu tiên, một câu hỏi bảo mật: Nếu trò chơi có pre_tasks и post_tasks (và không có nhiệm vụ hoặc vai trò nào), vậy có thể xảy ra sự cố gì đó nếu tôi thực hiện nhiệm vụ đầu tiên từ post_tasks Tôi sẽ chuyển nó đến cuối pre_tasks?

Tất nhiên, cách diễn đạt của câu hỏi gợi ý rằng nó sẽ bị hỏng. Nhưng chính xác thì sao?

... Người xử lý. Đọc những điều cơ bản cho thấy một thực tế quan trọng: tất cả các trình xử lý đều được tự động xóa sau mỗi phần. Những thứ kia. tất cả các nhiệm vụ từ pre_tasks, sau đó tất cả các trình xử lý đã được thông báo. Sau đó, tất cả các vai trò và tất cả các trình xử lý đã được thông báo trong các vai trò đó đều được thực thi. Sau đó post_tasks và những người xử lý chúng.

Vì vậy, nếu bạn kéo một tác vụ từ post_tasks в pre_tasks, thì có khả năng bạn sẽ thực thi nó trước khi trình xử lý được thực thi. ví dụ, nếu trong pre_tasks máy chủ web đã được cài đặt và cấu hình, và post_tasks một cái gì đó được gửi đến nó, sau đó chuyển nhiệm vụ này sang phần pre_tasks sẽ dẫn đến việc tại thời điểm “gửi” máy chủ vẫn chưa hoạt động và mọi thứ sẽ bị hỏng.

Bây giờ chúng ta hãy nghĩ lại, tại sao chúng ta cần pre_tasks и post_tasks? Ví dụ: để hoàn thành mọi thứ cần thiết (bao gồm cả người xử lý) trước khi hoàn thành vai trò. MỘT post_tasks sẽ cho phép chúng tôi làm việc với kết quả của các vai trò thực thi (bao gồm cả trình xử lý).

Một chuyên gia Ansible sắc sảo sẽ cho chúng ta biết nó là gì. meta: flush_handlers, nhưng tại sao chúng ta cần tuôn ra_handlers nếu chúng ta có thể dựa vào thứ tự thực hiện các phần đang chơi? Hơn nữa, việc sử dụng meta:flush_handlers có thể mang lại cho chúng ta những điều không mong muốn với các trình xử lý trùng lặp, đưa ra những cảnh báo lạ khi sử dụng when у block vân vân. Bạn càng biết rõ về ansible thì bạn càng có thể đặt tên cho một giải pháp “khó khăn” hơn. Và một giải pháp đơn giản - sử dụng sự phân chia tự nhiên giữa các vai trò trước/vai trò/hậu kỳ - không gây ra các sắc thái.

Và quay lại với 'foo' của chúng ta. Tôi nên đặt nó ở đâu? Trước, sau hay vai trò? Rõ ràng, điều này phụ thuộc vào việc chúng ta có cần kết quả của trình xử lý foo hay không. Nếu chúng không có ở đó thì foo không cần phải được đặt ở trước hoặc sau - những phần này có ý nghĩa đặc biệt - thực thi các tác vụ trước và sau phần thân chính của mã.

Bây giờ câu trả lời cho câu hỏi “vai trò hoặc nhiệm vụ” liên quan đến những gì đã được thực hiện - nếu có nhiệm vụ ở đó, thì bạn cần thêm chúng vào nhiệm vụ. Nếu có vai trò, bạn cần tạo vai trò (thậm chí từ một nhiệm vụ). Hãy để tôi nhắc bạn rằng nhiệm vụ và vai trò không được sử dụng cùng một lúc.

Hiểu những điều cơ bản về Ansible sẽ cung cấp câu trả lời hợp lý cho những câu hỏi có vẻ như về hương vị.

Nhiệm vụ và vai trò (phần hai)

Bây giờ hãy thảo luận về tình huống khi bạn mới bắt đầu viết playbook. Bạn cần làm foo, bar và baz. Đây là ba nhiệm vụ, một vai trò hay ba vai trò? Để tóm tắt câu hỏi: bạn nên bắt đầu viết vai vào thời điểm nào? Viết vai trò để làm gì khi bạn có thể viết nhiệm vụ?... Vai trò là gì?

Một trong những sai lầm lớn nhất (tôi đã nói về điều này) là nghĩ rằng một vai trò giống như một chức năng trong thư viện của chương trình. Mô tả chức năng chung trông như thế nào? Nó chấp nhận các đối số đầu vào, tương tác với các nguyên nhân phụ, thực hiện các tác dụng phụ và trả về một giá trị.

Bây giờ, chú ý. Những gì có thể được thực hiện từ vai trò này? Bạn luôn có thể thoải mái gọi các tác dụng phụ, đây là bản chất của toàn bộ Ansible - tạo ra các tác dụng phụ. Có nguyên nhân phụ? Tiểu học. Nhưng với “chuyển một giá trị và trả lại” - đó là lúc nó không hoạt động. Đầu tiên, bạn không thể chuyển giá trị cho một vai trò. Bạn có thể đặt biến toàn cục có thời lượng phát trong thời gian tồn tại trong phần vars cho vai trò. Bạn có thể đặt một biến toàn cục có thời gian tồn tại bên trong vai trò. Hoặc thậm chí với tuổi thọ của playbook (set_fact/register). Nhưng bạn không thể có "biến cục bộ". Bạn không thể "lấy một giá trị" và "trả lại giá trị đó".

Điều chính tiếp theo là: bạn không thể viết một cái gì đó trong Ansible mà không gây ra tác dụng phụ. Thay đổi các biến toàn cục luôn là một tác dụng phụ đối với một hàm. Ví dụ, trong Rust, việc thay đổi một biến toàn cục là unsafe. Và trong Ansible, đây là phương pháp duy nhất tác động đến giá trị của một vai trò. Lưu ý các từ được sử dụng: không phải "chuyển một giá trị cho vai trò" mà là "thay đổi các giá trị mà vai trò sử dụng". Không có sự tách biệt giữa các vai trò. Không có sự tách biệt giữa nhiệm vụ và vai trò.

Tổng số: một vai trò không phải là một chức năng.

Vai diễn này có gì hay? Đầu tiên, vai trò có giá trị mặc định (/default/main.yaml), thứ hai, vai trò này có các thư mục bổ sung để lưu trữ tệp.

Lợi ích của giá trị mặc định là gì? Bởi vì trong kim tự tháp của Maslow, bảng ưu tiên thay đổi khá sai lầm của Ansible, các giá trị mặc định của vai trò có mức độ ưu tiên thấp nhất (trừ các tham số dòng lệnh Ansible). Điều này có nghĩa là nếu bạn cần cung cấp các giá trị mặc định và không lo lắng về việc chúng sẽ ghi đè các giá trị từ biến khoảng không quảng cáo hoặc nhóm, thì mặc định vai trò là nơi duy nhất phù hợp với bạn. (Tôi nói dối một chút - còn nhiều nữa |d(your_default_here), nhưng nếu chúng ta nói về những nơi đứng yên thì chỉ có vai trò mặc định).

Còn điều gì tuyệt vời về các vai diễn này? Bởi vì họ có danh mục riêng của họ. Đây là các thư mục cho các biến, cả hằng số (tức là được tính cho vai trò) và động (có mẫu hoặc mẫu chống - include_vars cùng với {{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml.). Đây là những thư mục dành cho files/, templates/. Ngoài ra, nó cho phép bạn có các mô-đun và plugin của riêng mình (library/). Tuy nhiên, so với các nhiệm vụ trong một cuốn sách giải trí (cũng có thể có tất cả những điều này), lợi ích duy nhất ở đây là các tệp không được xếp vào một chồng mà thành nhiều chồng riêng biệt.

Thêm một chi tiết nữa: bạn có thể thử tạo các vai trò có sẵn để sử dụng lại (thông qua thiên hà). Với sự ra đời của các bộ sưu tập, việc phân bổ vai trò có thể được coi là gần như bị lãng quên.

Do đó, vai trò có hai tính năng quan trọng: chúng có giá trị mặc định (một tính năng duy nhất) và chúng cho phép bạn cấu trúc mã của mình.

Quay lại câu hỏi ban đầu: khi nào thực hiện nhiệm vụ và khi nào thực hiện vai trò? Các nhiệm vụ trong sổ tay thường được sử dụng làm chất “keo dán” trước/sau các vai trò hoặc như một thành phần xây dựng độc lập (khi đó sẽ không có vai trò nào trong mã). Một đống công việc bình thường xen lẫn với các vai trò là sự cẩu thả rõ ràng. Bạn nên tuân theo một phong cách cụ thể - một nhiệm vụ hoặc một vai trò. Vai trò cung cấp sự tách biệt giữa các thực thể và mặc định, các tác vụ cho phép bạn đọc mã nhanh hơn. Thông thường, nhiều mã “cố định” (quan trọng và phức tạp) được đưa vào các vai trò và các tập lệnh phụ trợ được viết theo kiểu nhiệm vụ.

Bạn có thể thực hiện import_role như một nhiệm vụ, nhưng nếu bạn viết điều này thì hãy chuẩn bị để giải thích cho cảm nhận của riêng bạn về vẻ đẹp của lý do tại sao bạn muốn làm điều này.

Một người đọc tinh tường có thể nói rằng các vai trò có thể nhập các vai trò, các vai trò có thể có sự phụ thuộc thông qua galaxy.yml, và cũng có một điều khủng khiếp và khủng khiếp include_role — Tôi nhắc bạn rằng chúng tôi đang cải thiện các kỹ năng trong Ansible cơ bản chứ không phải trong thể dục dụng cụ.

Trình xử lý và nhiệm vụ

Hãy thảo luận về một điều hiển nhiên khác: trình xử lý. Biết cách sử dụng chúng một cách chính xác gần như là một nghệ thuật. Sự khác biệt giữa trình xử lý và thao tác kéo là gì?

Vì chúng ta đang ghi nhớ những điều cơ bản nên đây là một ví dụ:

- hosts: group1
  tasks:
    - foo:
      notify: handler1
  handlers:
     - name: handler1
       bar:

Trình xử lý của vai trò được đặt trong rolename/handlers/main.yaml. Trình xử lý lục lọi giữa tất cả những người tham gia trò chơi: pre/post_tasks có thể kéo trình xử lý vai trò và một vai trò có thể kéo trình xử lý ra khỏi vở kịch. Tuy nhiên, các lệnh gọi "vai trò chéo" tới trình xử lý gây ra nhiều vấn đề hơn so với việc lặp lại một trình xử lý tầm thường. (Một yếu tố khác của các phương pháp hay nhất là cố gắng không lặp lại tên trình xử lý).

Sự khác biệt chính là tác vụ luôn được thực thi (idempotent) (thẻ cộng/trừ và when) và trình xử lý - theo thay đổi trạng thái (chỉ thông báo kích hoạt nếu nó đã được thay đổi). Điều đó có nghĩa là gì? Ví dụ, khi bạn khởi động lại, nếu không có thay đổi nào thì sẽ không có trình xử lý. Tại sao chúng ta cần thực thi trình xử lý khi không có thay đổi nào trong tác vụ tạo? Ví dụ: vì có thứ gì đó bị hỏng và thay đổi nhưng việc thực thi không đến được với người xử lý. Ví dụ, vì mạng tạm thời ngừng hoạt động. Cấu hình đã thay đổi, dịch vụ chưa được khởi động lại. Lần tiếp theo bạn khởi động nó, cấu hình sẽ không còn thay đổi nữa và dịch vụ vẫn giữ nguyên phiên bản cấu hình cũ.

Không thể giải quyết tình huống với cấu hình (chính xác hơn là bạn có thể phát minh ra một giao thức khởi động lại đặc biệt cho mình bằng cờ tệp, v.v., nhưng đây không còn là 'ansible cơ bản' dưới mọi hình thức). Nhưng có một câu chuyện phổ biến khác: chúng tôi cài ứng dụng, ghi lại .service-file, và bây giờ chúng tôi muốn nó daemon_reload и state=started. Và nơi tự nhiên cho việc này dường như là người xử lý. Nhưng nếu bạn đặt nó không phải là một trình xử lý mà là một nhiệm vụ ở cuối danh sách nhiệm vụ hoặc vai trò thì nó sẽ được thực thi bình thường mọi lúc. Ngay cả khi playbook bị hỏng ở giữa. Điều này hoàn toàn không giải quyết được vấn đề được khởi động lại (bạn không thể thực hiện một tác vụ với thuộc tính được khởi động lại vì tính tạm thời bị mất), nhưng chắc chắn đáng làm là state=started, độ ổn định tổng thể của playbook sẽ tăng lên, bởi vì số lượng kết nối và trạng thái động giảm.

Một đặc tính tích cực khác của trình xử lý là nó không làm tắc nghẽn đầu ra. Không có thay đổi nào - không bị bỏ qua thêm hoặc kết quả đầu ra ok - dễ đọc hơn. Nó cũng là một thuộc tính phủ định - nếu bạn tìm thấy lỗi đánh máy trong một tác vụ được thực thi tuyến tính trong lần chạy đầu tiên thì trình xử lý sẽ chỉ được thực thi khi được thay đổi, tức là. trong một số điều kiện - rất hiếm khi. Ví dụ, lần đầu tiên trong đời tôi vào XNUMX năm sau. Và tất nhiên, sẽ có lỗi đánh máy trong tên và mọi thứ sẽ hỏng. Và nếu bạn không chạy chúng lần thứ hai thì cũng không có gì thay đổi.

Riêng biệt, chúng ta cần nói về sự sẵn có của các biến. Ví dụ: nếu bạn thông báo một tác vụ bằng một vòng lặp, thì các biến sẽ có gì? Bạn có thể đoán theo cách phân tích, nhưng không phải lúc nào cũng tầm thường, đặc biệt nếu các biến số đến từ những nơi khác nhau.

... Vì vậy, các trình xử lý ít hữu ích hơn nhiều và có nhiều vấn đề hơn chúng tưởng. Nếu bạn có thể viết thứ gì đó đẹp mắt (không rườm rà) mà không cần người xử lý, thì tốt hơn hết là bạn nên làm điều đó mà không cần đến họ. Nếu mọi chuyện không suôn sẻ thì tốt hơn với họ.

Người đọc ăn mòn đã chỉ ra một cách đúng đắn rằng chúng ta chưa thảo luận listenrằng trình xử lý có thể gọi thông báo cho một trình xử lý khác, rằng trình xử lý có thể bao gồm import_tasks (có thể thực hiện include_role với with_items), rằng hệ thống xử lý trong Ansible là Turing-complete, rằng các trình xử lý từ include_role giao nhau một cách kỳ lạ với các trình xử lý từ play, v.v. .d. - tất cả những điều này rõ ràng không phải là "cơ bản").

Mặc dù có một WTF cụ thể thực sự là một tính năng mà bạn cần ghi nhớ. Nếu nhiệm vụ của bạn được thực thi với delegate_to và nó có thông báo thì trình xử lý tương ứng sẽ được thực thi mà không cần delegate_to, I E. trên máy chủ nơi trò chơi được chỉ định. (Tất nhiên, mặc dù người xử lý có thể có delegate_to Như nhau).

Riêng biệt, tôi muốn nói vài lời về các vai trò có thể tái sử dụng. Trước khi các bộ sưu tập xuất hiện, đã có ý tưởng rằng bạn có thể tạo ra những vai trò phổ quát có thể ansible-galaxy install và đã đi. Hoạt động trên tất cả các hệ điều hành của tất cả các biến thể trong mọi tình huống. Vì vậy, ý kiến ​​​​của tôi: nó không hoạt động. Bất kỳ vai trò nào với số lượng lớn include_vars, hỗ trợ 100500 trường hợp, chắc chắn sẽ rơi vào vực thẳm của các lỗi góc. Chúng có thể được bao phủ bằng thử nghiệm lớn, nhưng giống như bất kỳ thử nghiệm nào, hoặc bạn có tích Descartes gồm các giá trị đầu vào và hàm tổng hoặc bạn có “các kịch bản riêng lẻ được bao phủ”. Ý kiến ​​​​của tôi là sẽ tốt hơn nhiều nếu vai trò là tuyến tính (độ phức tạp chu kỳ 1).

Càng ít if (rõ ràng hoặc khai báo - ở dạng when hoặc hình thức include_vars theo tập hợp các biến), vai trò càng tốt. Đôi khi bạn phải tạo cành, nhưng tôi nhắc lại, càng ít cành thì càng tốt. Vì vậy, có vẻ như đây là một vai trò tốt với thiên hà (nó hoạt động!) với một loạt when có thể ít được ưa thích hơn vai trò “của riêng mình” trong năm nhiệm vụ. Thời điểm mà vai trò của Galaxy tốt hơn chính là lúc bạn bắt đầu viết một điều gì đó. Thời điểm mọi chuyện trở nên tồi tệ hơn là khi có thứ gì đó bị vỡ và bạn nghi ngờ rằng đó là do “vai trò với thiên hà”. Bạn mở nó ra và có năm tập tin đính kèm, tám tờ nhiệm vụ và một chồng when'ov... Và chúng ta cần phải tìm ra điều này. Thay vì 5 nhiệm vụ, một danh sách tuyến tính không có gì phải phá vỡ.

Ở những phần sau

  • Một chút về khoảng không quảng cáo, biến nhóm, plugin Host_group_vars, Hostvars. Cách thắt nút Gordian bằng mì spaghetti. Các biến phạm vi và mức độ ưu tiên, mô hình bộ nhớ Ansible. “Vậy chúng ta lưu trữ tên người dùng cho cơ sở dữ liệu ở đâu?”
  • jinja: {{ jinja }} — nosql notype nosense nhựa mềm. Nó ở khắp mọi nơi, ngay cả ở những nơi bạn không ngờ tới. Một chút về !!unsafe và yaml ngon.

Nguồn: www.habr.com

Thêm một lời nhận xét