{"id":42280,"date":"2023-11-14T03:43:41","date_gmt":"2023-07-02T10:05:22","guid":{"rendered":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/"},"modified":"2024-01-15T11:21:36","modified_gmt":"2024-01-15T03:21:36","slug":"%e8%af%95%e7%94%a8ansible-molecule","status":"publish","type":"post","link":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/","title":{"rendered":"\u8bd5\u7528Ansible Molecule"},"content":{"rendered":"<h1>\u9996\u5148<\/h1>\n<p>\u6211\u5df2\u7ecf\u5c1d\u8bd5\u4f7f\u7528\u4e86Ansible Molecule\u3002\u8fd9\u662f\u4e00\u4e2a\u4ec5\u8bb0\u5f55\u4e86\u5728\u672c\u5730\u8fd0\u884c\u7684\u5185\u5bb9\u7684\u9875\u9762\u3002<\/p>\n<p>\u6b64\u5916\uff0c\u8fd8\u6709\u4ee5\u4e0bGetting Started\u4f5c\u4e3a\u5b98\u65b9\u6587\u6863\u63d0\u4f9b\u3002<br \/>\nhttps:\/\/ansible.readthedocs.io\/projects\/molecule\/working\/getting_started\/getting_started\/<\/p>\n<p>\u5c3d\u7ba1\u6ca1\u6709\u5b8c\u5168\u6309\u7167\u4e0a\u8ff0\u6b65\u9aa4\u8fdb\u884c\u64cd\u4f5c\uff0c\u4f46\u4e3a\u4e86\u5728\u672c\u5730\u91cd\u65b0\u521b\u5efaAnsible Molecule\uff0c\u7531\u4e8e\u7f3a\u4e4f\u6587\u6863\uff0c\u6211\u8fdb\u884c\u4e86\u591a\u6b21\u5c1d\u8bd5\u548c\u9519\u8bef\uff0c\u6240\u4ee5\u5c06\u5176\u4f5c\u4e3a\u5907\u5fd8\u5f55\u7559\u4e0b\u6765\u3002<\/p>\n<h1>\u5047\u8bbe<\/h1>\n<p>\u5728\u8fd9\u91cc\uff0c\u4ec5\u4f9b\u53c2\u8003\uff0c\u6211\u51b3\u5b9a\u4ee5&#8221;ansible-galaxy install nginxinc.nginx&#8221;\u5b89\u88c5\u7684\u96c6\u5408\u7684\u76ee\u5f55\u5e03\u5c40\u4f5c\u4e3a\u53c2\u8003\u6765\u521b\u5efa\u3002<br \/>\n\u7531\u4e8e\u6211\u662f\u521d\u5b66\u8005\u5e76\u4e14\u4e0d\u719f\u6089\u6700\u4f73\u76ee\u5f55\u5b9e\u8df5\uff0c\u6240\u4ee5\u6211\u501f\u9274\u4e86\u524d\u4eba\u7684\u4f8b\u5b50\u3002<\/p>\n<pre class=\"post-pre\"><code>$ tree ~\/.ansible\/roles\/nginxinc.nginx\r\n~\/.ansible\/roles\/nginxinc.nginx\r\n\u251c\u2500\u2500 CHANGELOG.md\r\n\u251c\u2500\u2500 CODE_OF_CONDUCT.md\r\n\u251c\u2500\u2500 CONTRIBUTING.md\r\n\u251c\u2500\u2500 LICENSE\r\n\u251c\u2500\u2500 README.md\r\n\u251c\u2500\u2500 SUPPORT.md\r\n\u251c\u2500\u2500 defaults\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 amplify.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 bsd.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 logrotate.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 main.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 selinux.yml\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 systemd.yml\r\n\u251c\u2500\u2500 files\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 license\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 services\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 nginx.conf.upstart\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 nginx.openrc\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 nginx.override.conf\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 nginx.systemd\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 nginx.sysvinit\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 nginx.upstart\r\n\u251c\u2500\u2500 handlers\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 meta\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 molecule\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 common\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 Dockerfile.j2\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 default\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 converge.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 molecule.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 verify.yml\r\n\r\n(snip)\r\n\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 upgrade-plus\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 converge.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 molecule.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 prepare.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 verify.yml\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 version\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 converge.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 molecule.yml\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 verify.yml\r\n\u251c\u2500\u2500 tasks\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 amplify\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 install-amplify.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 setup-debian.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 setup-redhat.yml\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 config\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 debug-output.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 modify-systemd.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 setup-logrotate.yml\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 keys\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 setup-keys.yml\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 main.yml\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 modules\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 install-modules.yml\r\n\r\n(snip)\r\n\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 prerequisites\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 install-dependencies.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u251c\u2500\u2500 prerequisites.yml\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 setup-selinux.yml\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 validate\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 validate.yml\r\n\u251c\u2500\u2500 templates\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 logrotate\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx.j2\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 selinux\r\n\u2502\u00a0\u00a0 \u2502\u00a0\u00a0 \u2514\u2500\u2500 nginx-plus-module.te.j2\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 services\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 nginx.service.override.conf.j2\r\n\u2514\u2500\u2500 vars\r\n    \u2514\u2500\u2500 main.yml\r\n\r\n35 directories, 96 files\r\n<\/code><\/pre>\n<h1>\u5728\u8bbe\u5907\u8fdb\u884c\u4e86\u9a8c\u8bc1\u6b65\u9aa4\u3002<\/h1>\n<p>\u53ea\u662f\u4e3a\u4e86\u53c2\u8003\uff0c\u6211\u4f1a\u9644\u4e0a\u9a8c\u8bc1\u8fd9\u4e2a\u6b65\u9aa4\u7684\u73af\u5883\u4fe1\u606f\u3002<\/p>\n<pre class=\"post-pre\"><code>$ lsb_release -a\r\nNo LSB modules are available.\r\nDistributor ID:\tUbuntu\r\nDescription:\tUbuntu 22.04.1 LTS\r\nRelease:\t22.04\r\nCodename:\tjammy\r\n$ ansible --version\r\nansible [core 2.15.2]\r\n  config file = \/etc\/ansible\/ansible.cfg\r\n  configured module search path = ['\/home\/tsuyoshi\/.ansible\/plugins\/modules', '\/usr\/share\/ansible\/plugins\/modules']\r\n  ansible python module location = \/usr\/lib\/python3\/dist-packages\/ansible\r\n  ansible collection location = \/home\/tsuyoshi\/.ansible\/collections:\/usr\/share\/ansible\/collections\r\n  executable location = \/usr\/bin\/ansible\r\n  python version = 3.10.6 (main, May 29 2023, 11:10:38) [GCC 11.3.0] (\/usr\/bin\/python3)\r\n  jinja version = 3.1.2\r\n  libyaml = True\r\n$ molecule --version\r\nmolecule 6.0.2 using python 3.10 \r\n    ansible:2.15.2\r\n    azure:23.5.0 from molecule_plugins\r\n    containers:23.5.0 from molecule_plugins requiring collections: ansible.posix&gt;=1.3.0 community.docker&gt;=1.9.1 containers.podman&gt;=1.8.1\r\n    default:6.0.2 from molecule\r\n    docker:23.5.0 from molecule_plugins requiring collections: community.docker&gt;=3.0.2 ansible.posix&gt;=1.4.0\r\n    ec2:23.5.0 from molecule_plugins\r\n    gce:23.5.0 from molecule_plugins requiring collections: google.cloud&gt;=1.0.2 community.crypto&gt;=1.8.0\r\n    podman:23.5.0 from molecule_plugins requiring collections: containers.podman&gt;=1.7.0 ansible.posix&gt;=1.3.0\r\n    vagrant:23.5.0 from molecule_plugins\r\n<\/code><\/pre>\n<h1>\u66ab\u6642\u7684\u624b\u9806, \u76f4\u5230\u5728\u624b\u908a\u904b\u4f5c\u70ba\u6b62\u3002<\/h1>\n<p>\u9996\u5148\uff0c\u751f\u6210Ansible\u96c6\u5408\u7684\u6a21\u677f\u3002<br \/>\nazarashi.utils\u662f\u4e00\u4e2a\u7531\u547d\u540d\u7a7a\u95f4\u540d\u548c\u96c6\u5408\u540d\u62fc\u63a5\u800c\u6210\u7684\u5b57\u7b26\u4e32\u3002<\/p>\n<pre class=\"post-pre\"><code>$ ansible-galaxy collection init azarashi.utils\r\n- Collection azarashi.utils was created successfully\r\n$ tree .\r\n.\r\n\u2514\u2500\u2500 azarashi\r\n    \u2514\u2500\u2500 utils\r\n        \u251c\u2500\u2500 README.md\r\n        \u251c\u2500\u2500 docs\r\n        \u251c\u2500\u2500 galaxy.yml\r\n        \u251c\u2500\u2500 meta\r\n        \u2502\u00a0\u00a0 \u2514\u2500\u2500 runtime.yml\r\n        \u251c\u2500\u2500 plugins\r\n        \u2502\u00a0\u00a0 \u2514\u2500\u2500 README.md\r\n        \u2514\u2500\u2500 roles\r\n\r\n6 directories, 4 files\r\n<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\uff0c\u6211\u4eec\u5c06\u751f\u6210\u89d2\u8272\u7684\u6a21\u677f\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cd azarashi\/utils\/roles\/\r\n$ ansible-galaxy role init azarashi.utils\r\n- Role azarashi.utils was created successfully\r\n$ tree .\r\n.\r\n\u2514\u2500\u2500 azarashi.utils\r\n    \u251c\u2500\u2500 README.md\r\n    \u251c\u2500\u2500 defaults\r\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n    \u251c\u2500\u2500 files\r\n    \u251c\u2500\u2500 handlers\r\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n    \u251c\u2500\u2500 meta\r\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n    \u251c\u2500\u2500 tasks\r\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n    \u251c\u2500\u2500 templates\r\n    \u251c\u2500\u2500 tests\r\n    \u2502\u00a0\u00a0 \u251c\u2500\u2500 inventory\r\n    \u2502\u00a0\u00a0 \u2514\u2500\u2500 test.yml\r\n    \u2514\u2500\u2500 vars\r\n        \u2514\u2500\u2500 main.yml\r\n\r\n9 directories, 8 files\r\n<\/code><\/pre>\n<p>\u5728\u8f6c\u81f3 azarashi.utils \u540e\uff0c\u5c06 molecule \u7684\u6a21\u677f\u6307\u5b9a\u4e3a &#8220;helloworld&#8221; \u4f5c\u4e3a\u4e00\u4e2a\u573a\u666f\u3002<\/p>\n<p>\u5bf9\u4e8e\u9a8c\u8bc1\u89d2\u8272\u7684\u5305\u5b89\u88c5\u573a\u666f\uff0c\u573a\u666f\u540d\u79f0\u53ef\u80fd\u4f1a\u662f &#8220;install&#8221;\u3001&#8221;uninstall&#8221; \u6216 &#8220;update&#8221;\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cd azarashi.utils\/\r\n$ molecule init scenario helloworld\r\nINFO     Initializing new scenario helloworld...\r\n\r\nPLAY [Create a new molecule scenario] ******************************************\r\n\r\nTASK [Check if destination folder exists] **************************************\r\nchanged: [localhost]\r\n\r\nTASK [Check if destination folder is empty] ************************************\r\nok: [localhost]\r\n\r\nTASK [Fail if destination folder is not empty] *********************************\r\nskipping: [localhost]\r\n\r\nTASK [Expand templates] ********************************************************\r\nchanged: [localhost] =&gt; (item=molecule\/helloworld\/create.yml)\r\nchanged: [localhost] =&gt; (item=molecule\/helloworld\/converge.yml)\r\nchanged: [localhost] =&gt; (item=molecule\/helloworld\/molecule.yml)\r\nchanged: [localhost] =&gt; (item=molecule\/helloworld\/destroy.yml)\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0\r\n\r\nINFO     Initialized scenario in \/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils\/molecule\/helloworld successfully.\r\n<\/code><\/pre>\n<p>\u901a\u8fc7\u6267\u884c\u4e0a\u9762\u7684\u547d\u4ee4\uff0c\u4f1a\u751f\u6210molecule\u76ee\u5f55\uff0c\u5e76\u5728\u5176\u4e0b\u751f\u6210helloworld\u6216molecule\u6240\u9700\u7684yml\u6587\u4ef6\u3002<\/p>\n<pre class=\"post-pre\"><code>$ tree .\r\n.\r\n\u251c\u2500\u2500 README.md\r\n\u251c\u2500\u2500 defaults\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 files\r\n\u251c\u2500\u2500 handlers\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 meta\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 molecule\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 helloworld\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 converge.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 create.yml\r\n\u2502\u00a0\u00a0     \u251c\u2500\u2500 destroy.yml\r\n\u2502\u00a0\u00a0     \u2514\u2500\u2500 molecule.yml\r\n\u251c\u2500\u2500 tasks\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 main.yml\r\n\u251c\u2500\u2500 templates\r\n\u251c\u2500\u2500 tests\r\n\u2502\u00a0\u00a0 \u251c\u2500\u2500 inventory\r\n\u2502\u00a0\u00a0 \u2514\u2500\u2500 test.yml\r\n\u2514\u2500\u2500 vars\r\n    \u2514\u2500\u2500 main.yml\r\n\r\n10 directories, 12 files\r\n<\/code><\/pre>\n<p>\u76ee\u524d\u4e3a\u6b62\uff0c\u51c6\u5907\u5de5\u4f5c\u5df2\u7ecf\u5b8c\u6210\u3002<\/p>\n<p>\u5728&#8221;molecule&#8221;\u6d4b\u8bd5\u4e2d\uff0c\u9ed8\u8ba4\u60c5\u51b5\u4e0b\u4f1a\u5728\u5f53\u524d\u76ee\u5f55\u4e0b\u67e5\u627e\u76f8\u5bf9\u8def\u5f84\u4e3a&#8221;molecule\/default\/molecule.yml&#8221;\u7684\u6587\u4ef6\u3002\u4e3a\u4e86\u6307\u5b9a&#8221;helloworld&#8221;\u573a\u666f\u5e76\u5c06\u641c\u7d22\u8def\u5f84\u8bbe\u7f6e\u4e3a&#8221;molecule\/helloworld\/molecule.yml&#8221;\uff0c\u53ef\u4ee5\u901a\u8fc7\u4f7f\u7528&#8211;scenario-name\u9009\u9879\u6765\u5b9e\u73b0\u3002<\/p>\n<pre class=\"post-pre\"><code>$ pwd\r\n\/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils\r\n$ molecule test --scenario-name helloworld\r\nWARNING  The scenario config file ('\/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils\/molecule\/helloworld\/molecule.yml') has been modified since the scenario was created. If recent changes are important, reset the scenario with 'molecule destroy' to clean up created items or 'molecule reset' to clear current configuration.\r\nINFO     helloworld scenario test matrix: dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy\r\nINFO     Performing prerun with role_name_check=0...\r\nINFO     Running from \/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils : ansible-galaxy collection install -vvv --force ..\/..\r\nINFO     Running helloworld &gt; dependency\r\nWARNING  Skipping, missing the requirements file.\r\nWARNING  Skipping, missing the requirements file.\r\nINFO     Running helloworld &gt; cleanup\r\nWARNING  Skipping, cleanup playbook not configured.\r\nINFO     Running helloworld &gt; destroy\r\n\r\nPLAY [Destroy] *****************************************************************\r\n\r\nTASK [Populate instance config] ************************************************\r\nok: [localhost]\r\n\r\nTASK [Dump instance config] ****************************************************\r\nskipping: [localhost]\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0\r\n\r\nINFO     Running helloworld &gt; syntax\r\n\r\nplaybook: \/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils\/molecule\/helloworld\/converge.yml\r\nINFO     Running helloworld &gt; create\r\n\r\nPLAY [Create] ******************************************************************\r\n\r\nTASK [Populate instance config dict] *******************************************\r\nskipping: [localhost]\r\n\r\nTASK [Convert instance config dict to a list] **********************************\r\nskipping: [localhost]\r\n\r\nTASK [Dump instance config] ****************************************************\r\nskipping: [localhost]\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=0    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0\r\n\r\nINFO     Running helloworld &gt; prepare\r\nWARNING  Skipping, prepare playbook not configured.\r\nINFO     Running helloworld &gt; converge\r\n\r\nPLAY [Converge] ****************************************************************\r\n\r\nTASK [Replace this task with one that validates your content] ******************\r\nok: [instance] =&gt; {\r\n    \"msg\": \"This is the effective test\"\r\n}\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"msg\": \"This is the effective test\"\r\n}\r\n\r\nPLAY RECAP *********************************************************************\r\ninstance                   : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\nmolecule-ubuntu            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\n\r\nINFO     Running helloworld &gt; idempotence\r\n\r\nPLAY [Converge] ****************************************************************\r\n\r\nTASK [Replace this task with one that validates your content] ******************\r\nok: [instance] =&gt; {\r\n    \"msg\": \"This is the effective test\"\r\n}\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"msg\": \"This is the effective test\"\r\n}\r\n\r\nPLAY RECAP *********************************************************************\r\ninstance                   : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\nmolecule-ubuntu            : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\n\r\nINFO     Idempotence completed successfully.\r\nINFO     Running helloworld &gt; side_effect\r\nWARNING  Skipping, side effect playbook not configured.\r\nINFO     Running helloworld &gt; verify\r\nINFO     Running Ansible Verifier\r\nWARNING  Skipping, verify action has no playbook.\r\nINFO     Verifier completed successfully.\r\nINFO     Running helloworld &gt; cleanup\r\nWARNING  Skipping, cleanup playbook not configured.\r\nINFO     Running helloworld &gt; destroy\r\n\r\nPLAY [Destroy] *****************************************************************\r\n\r\nTASK [Populate instance config] ************************************************\r\nok: [localhost]\r\n\r\nTASK [Dump instance config] ****************************************************\r\nskipping: [localhost]\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0\r\n\r\nINFO     Pruning extra files from scenario ephemeral directory\r\n<\/code><\/pre>\n<p>\u6682\u65f6\u6211\u5df2\u7ecf\u6210\u529f\u6267\u884c\u4e86\u5206\u5b50\u6d4b\u8bd5\u3002<br \/>\n\u7136\u800c\uff0c\u6267\u884c\u7684\u4e3b\u673a\u672c\u8eab\u662f\u672c\u5730\u4e3b\u673a\uff0c\u53ef\u80fd\u4f1a\u7834\u574f\u4e3b\u673a\u73af\u5883\u3002<\/p>\n<p>\u6240\u4ee5\uff0c\u63a5\u4e0b\u6765\u6211\u4eec\u5c1d\u8bd5\u4f7f\u7528Docker\u955c\u50cf\u6765\u8fd0\u884c\u6d4b\u8bd5\u3002<\/p>\n<h1>\u76f4\u5230\u4f7f\u7528Docker\u955c\u50cf\u6267\u884c\u6d4b\u8bd5\u7684\u6b65\u9aa4\u3002<\/h1>\n<p>\u4e3a\u4e86\u5728Docker\u955c\u50cf\u4e2d\u6267\u884c\u6d4b\u8bd5\uff0c\u8bf7\u6574\u7406molecule\u5b50\u76ee\u5f55\u4e0b\u7684yml\u6587\u4ef6\u3002<\/p>\n<p>\u6211\u53c2\u8003\u4e86\u4e0b\u9762\u7684\u5b98\u65b9\u6587\u4ef6\uff08\u203b1\uff09\u3002<\/p>\n<ul class=\"post-ul\">https:\/\/ansible.readthedocs.io\/projects\/molecule\/docker\/<\/ul>\n<p>\u4e3a\u4e86\u6709\u610f\u8bc6\u5730\u4ececonverge.yml\u4e2d\u8c03\u7528\uff0c\u6211\u5c06\u5728\u4e3b\u4efb\u52a1\u4e2d\u6dfb\u52a0\u4ee5\u4e0b\u4efb\u52a1\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cat tasks\/main.yml \r\n---\r\n- name: Task is running from within the role\r\n  ansible.builtin.debug:\r\n    msg: \"This is a task from my_role.\"\r\n<\/code><\/pre>\n<p>\u7528\u4e0b\u8ff0\u5185\u5bb9\u51c6\u5907converge.yml\u6587\u4ef6\u3002(\u203b1)\u6587\u6863\u4e2d\u6dfb\u52a0\u8c03\u7528\u4e0a\u8ff0\u4efb\u52a1\u7684\u6761\u76ee\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cat molecule\/helloworld\/converge.yml \r\n- name: Fail if molecule group is missing\r\n  hosts: localhost\r\n  tasks:\r\n    - name: Print some info\r\n      ansible.builtin.debug:\r\n        msg: \"{{ groups }}\"\r\n\r\n    - name: Assert group existence\r\n      ansible.builtin.assert:\r\n        that: \"'molecule' in groups\"\r\n        fail_msg: |\r\n          molecule group was not found inside inventory groups: {{ groups }}\r\n\r\n- name: Converge\r\n  hosts: molecule\r\n  # We disable gather facts because it would fail due to our container not\r\n  # having python installed. This will not prevent use from running 'raw'\r\n  # commands. Most molecule users are expected to use containers that already\r\n  # have python installed in order to avoid notable delays installing it.\r\n  gather_facts: false\r\n  tasks:\r\n    - name: Check uname\r\n      ansible.builtin.raw: uname -a\r\n      register: result\r\n      changed_when: false\r\n\r\n    - name: Print some info\r\n      ansible.builtin.assert:\r\n        that: result.stdout | regex_search(\"^Linux\")\r\n\r\n    - name: Azarashi's Testing role\r\n      ansible.builtin.include_role:\r\n        name: azarashi.utils\r\n        tasks_from: main.yml\r\n<\/code><\/pre>\n<p>\u63a5\u4e0b\u6765\uff0c\u51c6\u5907create.yml\uff0cdestroy.yml\uff0cmolecule.yml\u548crequirements.yml\u3002\u5b83\u4eec\u7684\u5185\u5bb9\u4e0e(\u203b1)\u76f8\u540c\u3002<\/p>\n<pre class=\"post-pre\"><code>$ cat molecule\/helloworld\/create.yml \r\n- name: Create\r\n  hosts: localhost\r\n  gather_facts: false\r\n  vars:\r\n    molecule_inventory:\r\n      all:\r\n        hosts: {}\r\n        molecule: {}\r\n  tasks:\r\n    - name: Create a container\r\n      community.docker.docker_container:\r\n        name: \"{{ item.name }}\"\r\n        image: \"{{ item.image }}\"\r\n        state: started\r\n        command: sleep 1d\r\n        log_driver: json-file\r\n      register: result\r\n      loop: \"{{ molecule_yml.platforms }}\"\r\n\r\n    - name: Print some info\r\n      ansible.builtin.debug:\r\n        msg: \"{{ result.results }}\"\r\n\r\n    - name: Fail if container is not running\r\n      when: &gt;\r\n        item.container.State.ExitCode != 0 or\r\n        not item.container.State.Running\r\n      ansible.builtin.include_tasks:\r\n        file: tasks\/create-fail.yml\r\n      loop: \"{{ result.results }}\"\r\n      loop_control:\r\n        label: \"{{ item.container.Name }}\"\r\n\r\n    - name: Add container to molecule_inventory\r\n      vars:\r\n        inventory_partial_yaml: |\r\n          all:\r\n            children:\r\n              molecule:\r\n                hosts:\r\n                  \"{{ item.name }}\":\r\n                    ansible_connection: community.docker.docker\r\n      ansible.builtin.set_fact:\r\n        molecule_inventory: &gt;\r\n          {{ molecule_inventory | combine(inventory_partial_yaml | from_yaml) }}\r\n      loop: \"{{ molecule_yml.platforms }}\"\r\n      loop_control:\r\n        label: \"{{ item.name }}\"\r\n\r\n    - name: Dump molecule_inventory\r\n      ansible.builtin.copy:\r\n        content: |\r\n          {{ molecule_inventory | to_yaml }}\r\n        dest: \"{{ molecule_ephemeral_directory }}\/inventory\/molecule_inventory.yml\"\r\n        mode: 0600\r\n\r\n    - name: Force inventory refresh\r\n      ansible.builtin.meta: refresh_inventory\r\n\r\n    - name: Fail if molecule group is missing\r\n      ansible.builtin.assert:\r\n        that: \"'molecule' in groups\"\r\n        fail_msg: |\r\n          molecule group was not found inside inventory groups: {{ groups }}\r\n      run_once: true # noqa: run-once[task]\r\n\r\n# we want to avoid errors like \"Failed to create temporary directory\"\r\n- name: Validate that inventory was refreshed\r\n  hosts: molecule\r\n  gather_facts: false\r\n  tasks:\r\n    - name: Check uname\r\n      ansible.builtin.raw: uname -a\r\n      register: result\r\n      changed_when: false\r\n\r\n    - name: Display uname info\r\n      ansible.builtin.debug:\r\n        msg: \"{{ result.stdout }}\"\r\n<\/code><\/pre>\n<pre class=\"post-pre\"><code>$ cat molecule\/helloworld\/destroy.yml \r\n- name: Destroy molecule containers\r\n  hosts: molecule\r\n  gather_facts: false\r\n  tasks:\r\n    - name: Stop and remove container\r\n      delegate_to: localhost\r\n      community.docker.docker_container:\r\n        name: \"{{ inventory_hostname }}\"\r\n        state: absent\r\n        auto_remove: true\r\n\r\n- name: Remove dynamic molecule inventory\r\n  hosts: localhost\r\n  gather_facts: false\r\n  tasks:\r\n    - name: Remove dynamic inventory file\r\n      ansible.builtin.file:\r\n        path: \"{{ molecule_ephemeral_directory }}\/inventory\/molecule_inventory.yml\"\r\n        state: absent\r\n<\/code><\/pre>\n<pre class=\"post-pre\"><code>$ cat molecule\/helloworld\/molecule.yml \r\ndependency:\r\n  name: galaxy\r\n  options:\r\n    requirements-file: requirements.yml\r\nplatforms:\r\n  - name: molecule-ubuntu\r\n    image: ubuntu:18.04\r\n<\/code><\/pre>\n<pre class=\"post-pre\"><code>$ cat molecule\/helloworld\/reqirements.yml \r\ncollections:\r\n  - community.docker\r\n<\/code><\/pre>\n<p>\u56e0\u4e3a\u524d\u9762\u7684\u51c6\u5907\u5de5\u4f5c\u5df2\u7ecf\u5b8c\u6210\uff0c\u6240\u4ee5\u6211\u4eec\u73b0\u5728\u8fdb\u884c\u6267\u884c\uff0c\u4f46\u662f\u9700\u8981\u4e8b\u5148\u6ce8\u610f\u4e00\u4e0b\u662f\u5426\u5b58\u5728docker\u955c\u50cf\u3002<\/p>\n<pre class=\"post-pre\"><code>$ sudo docker ps -a\r\nCONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES\r\n$ molecule list\r\nINFO     Running helloworld &gt; list\r\n                  \u2577             \u2577                  \u2577               \u2577         \u2577            \r\n  Instance Name   \u2502 Driver Name \u2502 Provisioner Name \u2502 Scenario Name \u2502 Created \u2502 Converged  \r\n\u2576\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2574\r\n  molecule-ubuntu \u2502 default     \u2502 ansible          \u2502 helloworld    \u2502 false   \u2502 false      \r\n                  \u2575             \u2575                  \u2575               \u2575         \u2575         \r\n<\/code><\/pre>\n<p>\u4e3a\u4e86\u6267\u884cmolecule\u7684\u6d4b\u8bd5\uff0c\u901a\u8fc7\u4ee5\u4e0b\u547d\u4ee4\u8fdb\u884c\u64cd\u4f5c\u3002<br \/>\n\u7531\u4e8e\u6ca1\u6709\u9644\u52a0destroy=never\uff0c\u751f\u6210\u7684docker\u5bb9\u5668\u5c06\u4f1a\u88ab\u5220\u9664\uff0c\u6240\u4ee5\u6211\u4eec\u6545\u610f\u9644\u52a0\u4e86\u8be5\u9009\u9879\u3002<\/p>\n<pre class=\"post-pre\"><code>$ molecule test --scenario-name helloworld --destroy=never\r\nINFO     helloworld scenario test matrix: dependency, cleanup, destroy, syntax, create, prepare, converge, idempotence, side_effect, verify, cleanup, destroy\r\nINFO     Performing prerun with role_name_check=0...\r\nINFO     Running from \/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils : ansible-galaxy collection install -vvv --force ..\/..\r\nINFO     Running helloworld &gt; dependency\r\nWARNING  Skipping, missing the requirements file.\r\nWARNING  Skipping, missing the requirements file.\r\nINFO     Running helloworld &gt; cleanup\r\nWARNING  Skipping, cleanup playbook not configured.\r\nINFO     Running helloworld &gt; destroy\r\nWARNING  Skipping, '--destroy=never' requested.\r\nINFO     Running helloworld &gt; syntax\r\n[WARNING]: Could not match supplied host pattern, ignoring: molecule\r\n\r\nplaybook: \/home\/tsuyoshi\/test\/azarashi\/utils\/roles\/azarashi.utils\/molecule\/helloworld\/converge.yml\r\nINFO     Running helloworld &gt; create\r\n\r\nPLAY [Create] ******************************************************************\r\n\r\nTASK [Create a container] ******************************************************\r\nchanged: [localhost] =&gt; (item={'image': 'ubuntu:18.04', 'name': 'molecule-ubuntu'})\r\n\r\nTASK [Print some info] *********************************************************\r\nok: [localhost] =&gt; {\r\n    \"msg\": [\r\n        {\r\n            \"ansible_loop_var\": \"item\",\r\n\r\n(snip)\r\n\r\nTASK [Fail if container is not running] ****************************************\r\nskipping: [localhost] =&gt; (item=\/molecule-ubuntu) \r\nskipping: [localhost]\r\n\r\nTASK [Add container to molecule_inventory] *************************************\r\nok: [localhost] =&gt; (item=molecule-ubuntu)\r\n\r\nTASK [Dump molecule_inventory] *************************************************\r\nchanged: [localhost]\r\n\r\nTASK [Force inventory refresh] *************************************************\r\n\r\nTASK [Fail if molecule group is missing] ***************************************\r\nok: [localhost] =&gt; {\r\n    \"changed\": false,\r\n    \"msg\": \"All assertions passed\"\r\n}\r\n\r\nPLAY [Validate that inventory was refreshed] ***********************************\r\n\r\nTASK [Check uname] *************************************************************\r\nok: [molecule-ubuntu]\r\n\r\nTASK [Display uname info] ******************************************************\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"msg\": \"Linux af07e92dba0a 5.15.0-43-generic #46-Ubuntu SMP Tue Jul 12 10:30:17 UTC 2022 x86_64 x86_64 x86_64 GNU\/Linux\\n\"\r\n}\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0\r\nmolecule-ubuntu            : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\n\r\nINFO     Running helloworld &gt; prepare\r\nWARNING  Skipping, prepare playbook not configured.\r\nINFO     Running helloworld &gt; converge\r\n\r\nPLAY [Fail if molecule group is missing] ***************************************\r\n\r\nTASK [Gathering Facts] *********************************************************\r\nok: [localhost]\r\n\r\nTASK [Print some info] *********************************************************\r\nok: [localhost] =&gt; {\r\n    \"msg\": {\r\n        \"all\": [\r\n            \"molecule-ubuntu\"\r\n        ],\r\n        \"molecule\": [\r\n            \"molecule-ubuntu\"\r\n        ],\r\n        \"ungrouped\": []\r\n    }\r\n}\r\n\r\nTASK [Assert group existence] **************************************************\r\nok: [localhost] =&gt; {\r\n    \"changed\": false,\r\n    \"msg\": \"All assertions passed\"\r\n}\r\n\r\nPLAY [Converge] ****************************************************************\r\n\r\nTASK [Check uname] *************************************************************\r\nok: [molecule-ubuntu]\r\n\r\nTASK [Print some info] *********************************************************\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"changed\": false,\r\n    \"msg\": \"All assertions passed\"\r\n}\r\n\r\nTASK [Azarashi's Testing role] *************************************************\r\n\r\nTASK [azarashi.utils : Task is running from within the role] *******************\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"msg\": \"This is a task from my_role.\"\r\n}\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\nmolecule-ubuntu            : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\n\r\nINFO     Running helloworld &gt; idempotence\r\n\r\nPLAY [Fail if molecule group is missing] ***************************************\r\n\r\nTASK [Gathering Facts] *********************************************************\r\nok: [localhost]\r\n\r\nTASK [Print some info] *********************************************************\r\nok: [localhost] =&gt; {\r\n    \"msg\": {\r\n        \"all\": [\r\n            \"molecule-ubuntu\"\r\n        ],\r\n        \"molecule\": [\r\n            \"molecule-ubuntu\"\r\n        ],\r\n        \"ungrouped\": []\r\n    }\r\n}\r\n\r\nTASK [Assert group existence] **************************************************\r\nok: [localhost] =&gt; {\r\n    \"changed\": false,\r\n    \"msg\": \"All assertions passed\"\r\n}\r\n\r\nPLAY [Converge] ****************************************************************\r\n\r\nTASK [Check uname] *************************************************************\r\nok: [molecule-ubuntu]\r\n\r\nTASK [Print some info] *********************************************************\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"changed\": false,\r\n    \"msg\": \"All assertions passed\"\r\n}\r\n\r\nTASK [Azarashi's Testing role] *************************************************\r\n\r\nTASK [azarashi.utils : Task is running from within the role] *******************\r\nok: [molecule-ubuntu] =&gt; {\r\n    \"msg\": \"This is a task from my_role.\"\r\n}\r\n\r\nPLAY RECAP *********************************************************************\r\nlocalhost                  : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\nmolecule-ubuntu            : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\r\n\r\nINFO     Idempotence completed successfully.\r\nINFO     Running helloworld &gt; side_effect\r\nWARNING  Skipping, side effect playbook not configured.\r\nINFO     Running helloworld &gt; verify\r\nINFO     Running Ansible Verifier\r\nWARNING  Skipping, verify action has no playbook.\r\nINFO     Verifier completed successfully.\r\nINFO     Running helloworld &gt; cleanup\r\nWARNING  Skipping, cleanup playbook not configured.\r\nINFO     Running helloworld &gt; destroy\r\nWARNING  Skipping, '--destroy=never' requested.\r\n<\/code><\/pre>\n<p>\u60a8\u53ef\u4ee5\u4f7f\u7528\u4ee5\u4e0b\u65b9\u5f0f\u5c06\u8be5\u53e5\u5b50\u7ffb\u8bd1\u6210\u4e2d\u6587\uff1a<\/p>\n<p>\u5728\u6536\u655b\u65f6\uff0c\u6211\u4eec\u53ef\u4ee5\u786e\u8ba4\u5df2\u7ecf\u6267\u884c\u4e86\u4efb\u52a1\u4e3b\u6587\u4ef6\u4e2d\u6709\u610f\u8bbe\u7f6e\u7684\u4efb\u52a1\u3002\u6b64\u5916\uff0cPlaybook\u5c06\u4f1a\u6267\u884c\u4e24\u6b21\uff0c\u5305\u62ec\u786e\u8ba4\u5e42\u7b49\u6027\u3002<\/p>\n<p>\u6700\u540e\uff0c\u6211\u4eec\u8981\u786e\u8ba4\u901a\u8fc7\u5206\u5b50\u6d4b\u8bd5\u7684\u6267\u884c\uff0c\u5df2\u751f\u6210\u4e86 Docker \u6620\u50cf\u3002<\/p>\n<pre class=\"post-pre\"><code>$ sudo docker ps -a\r\nCONTAINER ID   IMAGE          COMMAND      CREATED              STATUS              PORTS     NAMES\r\naf07e92dba0a   ubuntu:18.04   \"sleep 1d\"   About a minute ago   Up About a minute             molecule-ubuntu\r\n$ molecule list\r\nINFO     Running helloworld &gt; list\r\n                  \u2577             \u2577                  \u2577               \u2577         \u2577            \r\n  Instance Name   \u2502 Driver Name \u2502 Provisioner Name \u2502 Scenario Name \u2502 Created \u2502 Converged  \r\n\u2576\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u253c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2574\r\n  molecule-ubuntu \u2502 default     \u2502 ansible          \u2502 helloworld    \u2502 true    \u2502 true       \r\n                  \u2575             \u2575                  \u2575               \u2575         \u2575         \r\n<\/code><\/pre>\n<h1>\u603b\u7ed3<\/h1>\n<p>\u6211\u5df2\u7ecf\u8bb0\u5f55\u4e86\u5728\u672c\u5730\u4e3b\u673a\u6216Docker\u955c\u50cf\u4e0a\u8fd0\u884cAnsible Molecule\u7684\u6b65\u9aa4\u3002<\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u9996\u5148 \u6211\u5df2\u7ecf\u5c1d\u8bd5\u4f7f\u7528\u4e86Ansible Molecule\u3002\u8fd9\u662f\u4e00\u4e2a\u4ec5\u8bb0\u5f55\u4e86\u5728\u672c\u5730\u8fd0\u884c\u7684\u5185\u5bb9\u7684\u9875\u9762\u3002 \u6b64\u5916\uff0c\u8fd8\u6709\u4ee5 [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-42280","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v21.5 (Yoast SEO v21.5) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>\u8bd5\u7528Ansible Molecule - Blog - Silicon Cloud<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.silicloud.com\/zh\/blog\/\u8bd5\u7528ansible-molecule\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"\u8bd5\u7528Ansible Molecule\" \/>\n<meta property=\"og:description\" content=\"\u9996\u5148 \u6211\u5df2\u7ecf\u5c1d\u8bd5\u4f7f\u7528\u4e86Ansible Molecule\u3002\u8fd9\u662f\u4e00\u4e2a\u4ec5\u8bb0\u5f55\u4e86\u5728\u672c\u5730\u8fd0\u884c\u7684\u5185\u5bb9\u7684\u9875\u9762\u3002 \u6b64\u5916\uff0c\u8fd8\u6709\u4ee5 [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.silicloud.com\/zh\/blog\/\u8bd5\u7528ansible-molecule\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog - Silicon Cloud\" \/>\n<meta property=\"article:published_time\" content=\"2023-07-02T10:05:22+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-01-15T03:21:36+00:00\" \/>\n<meta name=\"author\" content=\"\u6587, \u7fd4\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u4f5c\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"\u6587, \u7fd4\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 \u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/\",\"name\":\"\u8bd5\u7528Ansible Molecule - Blog - Silicon Cloud\",\"isPartOf\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\"},\"datePublished\":\"2023-07-02T10:05:22+00:00\",\"dateModified\":\"2024-01-15T03:21:36+00:00\",\"author\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/64d5cc7727fffbff2f9a2a8da1de3e5c\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#breadcrumb\"},\"inLanguage\":\"zh-Hans\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u9996\u9875\",\"item\":\"https:\/\/www.silicloud.com\/zh\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"\u8bd5\u7528Ansible Molecule\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#website\",\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/\",\"name\":\"Blog - Silicon Cloud\",\"description\":\"\",\"inLanguage\":\"zh-Hans\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/64d5cc7727fffbff2f9a2a8da1de3e5c\",\"name\":\"\u6587, \u7fd4\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/920c3d673e0bccacc98e5e6b7149bb3c22edd8d39cb753e5d7d7e471498118a1?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/920c3d673e0bccacc98e5e6b7149bb3c22edd8d39cb753e5d7d7e471498118a1?s=96&d=mm&r=g\",\"caption\":\"\u6587, \u7fd4\"},\"url\":\"https:\/\/www.silicloud.com\/zh\/blog\/author\/wenxiang\/\"},{\"@type\":\"ImageObject\",\"inLanguage\":\"zh-Hans\",\"@id\":\"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#local-main-organization-logo\",\"url\":\"\",\"contentUrl\":\"\",\"caption\":\"Blog - Silicon Cloud\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"\u8bd5\u7528Ansible Molecule - Blog - Silicon Cloud","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.silicloud.com\/zh\/blog\/\u8bd5\u7528ansible-molecule\/","og_locale":"zh_CN","og_type":"article","og_title":"\u8bd5\u7528Ansible Molecule","og_description":"\u9996\u5148 \u6211\u5df2\u7ecf\u5c1d\u8bd5\u4f7f\u7528\u4e86Ansible Molecule\u3002\u8fd9\u662f\u4e00\u4e2a\u4ec5\u8bb0\u5f55\u4e86\u5728\u672c\u5730\u8fd0\u884c\u7684\u5185\u5bb9\u7684\u9875\u9762\u3002 \u6b64\u5916\uff0c\u8fd8\u6709\u4ee5 [&hellip;]","og_url":"https:\/\/www.silicloud.com\/zh\/blog\/\u8bd5\u7528ansible-molecule\/","og_site_name":"Blog - Silicon Cloud","article_published_time":"2023-07-02T10:05:22+00:00","article_modified_time":"2024-01-15T03:21:36+00:00","author":"\u6587, \u7fd4","twitter_card":"summary_large_image","twitter_misc":{"\u4f5c\u8005":"\u6587, \u7fd4","\u9884\u8ba1\u9605\u8bfb\u65f6\u95f4":"11 \u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/","url":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/","name":"\u8bd5\u7528Ansible Molecule - Blog - Silicon Cloud","isPartOf":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website"},"datePublished":"2023-07-02T10:05:22+00:00","dateModified":"2024-01-15T03:21:36+00:00","author":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/64d5cc7727fffbff2f9a2a8da1de3e5c"},"breadcrumb":{"@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#breadcrumb"},"inLanguage":"zh-Hans","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u9996\u9875","item":"https:\/\/www.silicloud.com\/zh\/blog\/"},{"@type":"ListItem","position":2,"name":"\u8bd5\u7528Ansible Molecule"}]},{"@type":"WebSite","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#website","url":"https:\/\/www.silicloud.com\/zh\/blog\/","name":"Blog - Silicon Cloud","description":"","inLanguage":"zh-Hans"},{"@type":"Person","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/64d5cc7727fffbff2f9a2a8da1de3e5c","name":"\u6587, \u7fd4","image":{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/920c3d673e0bccacc98e5e6b7149bb3c22edd8d39cb753e5d7d7e471498118a1?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/920c3d673e0bccacc98e5e6b7149bb3c22edd8d39cb753e5d7d7e471498118a1?s=96&d=mm&r=g","caption":"\u6587, \u7fd4"},"url":"https:\/\/www.silicloud.com\/zh\/blog\/author\/wenxiang\/"},{"@type":"ImageObject","inLanguage":"zh-Hans","@id":"https:\/\/www.silicloud.com\/zh\/blog\/%e8%af%95%e7%94%a8ansible-molecule\/#local-main-organization-logo","url":"","contentUrl":"","caption":"Blog - Silicon Cloud"}]}},"_links":{"self":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/42280","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/comments?post=42280"}],"version-history":[{"count":2,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/42280\/revisions"}],"predecessor-version":[{"id":59003,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/posts\/42280\/revisions\/59003"}],"wp:attachment":[{"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/media?parent=42280"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/categories?post=42280"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.silicloud.com\/zh\/blog\/wp-json\/wp\/v2\/tags?post=42280"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}