ansible-expert by personamanagmentlayer/pcl
npx skills add https://github.com/personamanagmentlayer/pcl --skill ansible-expert提供 Ansible 的专家指导 - 使用声明式 YAML playbook 进行配置管理、应用部署和 IT 自动化。
# 使用 pip
pip install ansible
# 使用 apt (Ubuntu/Debian)
sudo apt update
sudo apt install ansible
# 使用 yum (RHEL/CentOS)
sudo yum install ansible
# 验证安装
ansible --version
# inventory/hosts
[webservers]
web1.example.com
web2.example.com ansible_host=192.168.1.10
[databases]
db1.example.com ansible_user=dbadmin
db2.example.com
[production:children]
webservers
databases
[production:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_connection=ssh
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_host: 192.168.1.10
databases:
hosts:
db1.example.com:
ansible_user: dbadmin
db2.example.com:
production:
children:
webservers:
databases:
vars:
ansible_python_interpreter: /usr/bin/python3
ansible_connection: ssh
#!/usr/bin/env python3
# inventory/aws_ec2.py
import json
import boto3
def get_inventory():
ec2 = boto3.client('ec2', region_name='us-east-1')
response = ec2.describe_instances(Filters=[
{'Name': 'instance-state-name', 'Values': ['running']}
])
inventory = {
'_meta': {'hostvars': {}},
'all': {'hosts': []},
'webservers': {'hosts': []},
'databases': {'hosts': []},
}
for reservation in response['Reservations']:
for instance in reservation['Instances']:
ip = instance['PrivateIpAddress']
tags = {tag['Key']: tag['Value'] for tag in instance.get('Tags', [])}
inventory['all']['hosts'].append(ip)
inventory['_meta']['hostvars'][ip] = {
'ansible_host': ip,
'instance_id': instance['InstanceId'],
'instance_type': instance['InstanceType'],
}
# 按角色标签分组
role = tags.get('Role', '')
if role in inventory:
inventory[role]['hosts'].append(ip)
return inventory
if __name__ == '__main__':
print(json.dumps(get_inventory(), indent=2))
# playbooks/webserver.yml
---
- name: 配置 Web 服务器
hosts: webservers
become: yes
vars:
app_port: 8080
app_user: webapp
tasks:
- name: 安装 nginx
apt:
name: nginx
state: present
update_cache: yes
- name: 启动并启用 nginx
systemd:
name: nginx
state: started
enabled: yes
- name: 复制 nginx 配置
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/default
mode: '0644'
notify: 重新加载 nginx
- name: 创建应用用户
user:
name: "{{ app_user }}"
state: present
shell: /bin/bash
handlers:
- name: 重新加载 nginx
systemd:
name: nginx
state: reloaded
# playbooks/deploy-app.yml
---
- name: 部署应用
hosts: webservers
become: yes
vars:
app_name: myapp
app_version: "{{ version | default('latest') }}"
app_port: 8080
deploy_user: deployer
pre_tasks:
- name: 检查必需变量是否已定义
assert:
that:
- app_name is defined
- app_version is defined
fail_msg: "必需变量未定义"
tasks:
- name: 创建部署目录
file:
path: "/opt/{{ app_name }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
- name: 下载应用制品
get_url:
url: "https://artifacts.example.com/{{ app_name }}/{{ app_version }}/{{ app_name }}.jar"
dest: "/opt/{{ app_name }}/{{ app_name }}-{{ app_version }}.jar"
mode: '0644'
register: download_result
- name: 创建 systemd 服务
template:
src: templates/app.service.j2
dest: "/etc/systemd/system/{{ app_name }}.service"
mode: '0644'
notify:
- 重新加载 systemd
- 重启应用
- name: 启用应用服务
systemd:
name: "{{ app_name }}"
enabled: yes
- name: 等待应用启动
wait_for:
port: "{{ app_port }}"
delay: 5
timeout: 60
when: download_result.changed
- name: 检查应用健康状态
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
retries: 3
delay: 5
post_tasks:
- name: 清理旧版本
shell: |
cd /opt/{{ app_name }}
ls -t {{ app_name }}-*.jar | tail -n +4 | xargs -r rm
args:
executable: /bin/bash
handlers:
- name: 重新加载 systemd
systemd:
daemon_reload: yes
- name: 重启应用
systemd:
name: "{{ app_name }}"
state: restarted
---
- name: 条件语句和循环示例
hosts: all
tasks:
- name: 安装软件包 (Debian)
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
when: ansible_os_family == "Debian"
- name: 安装软件包 (RedHat)
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
when: ansible_os_family == "RedHat"
- name: 创建用户
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'alice', groups: 'wheel' }
- { name: 'bob', groups: 'users' }
- { name: 'charlie', groups: 'developers' }
- name: 配置服务
systemd:
name: "{{ item.name }}"
state: "{{ item.state }}"
enabled: "{{ item.enabled }}"
loop:
- { name: 'nginx', state: 'started', enabled: yes }
- { name: 'postgresql', state: 'started', enabled: yes }
- { name: 'redis', state: 'started', enabled: yes }
- name: 基于条件设置事实
set_fact:
environment_type: "{{ 'production' if inventory_hostname in groups['production'] else 'development' }}"
- name: 调试条件
debug:
msg: "这是一个 {{ environment_type }} 服务器"
roles/
└── webserver/
├── defaults/
│ └── main.yml # 默认变量
├── files/
│ └── app.conf # 静态文件
├── handlers/
│ └── main.yml # 处理器
├── meta/
│ └── main.yml # 角色元数据和依赖项
├── tasks/
│ └── main.yml # 主任务列表
├── templates/
│ └── nginx.conf.j2 # Jinja2 模板
├── tests/
│ └── test.yml # 角色测试
└── vars/
└── main.yml # 角色变量
# roles/webserver/defaults/main.yml
---
nginx_port: 80
nginx_user: www-data
document_root: /var/www/html
# roles/webserver/tasks/main.yml
---
- name: 安装 nginx
apt:
name: nginx
state: present
update_cache: yes
- name: 复制 nginx 配置
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: 重启 nginx
- name: 创建文档根目录
file:
path: "{{ document_root }}"
state: directory
owner: "{{ nginx_user }}"
mode: '0755'
- name: 启动 nginx
systemd:
name: nginx
state: started
enabled: yes
# roles/webserver/handlers/main.yml
---
- name: 重启 nginx
systemd:
name: nginx
state: restarted
# roles/webserver/templates/nginx.conf.j2
user {{ nginx_user }};
worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen {{ nginx_port }};
server_name {{ ansible_hostname }};
root {{ document_root }};
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}
# 在 playbook 中使用角色
---
- name: 配置 Web 服务器
hosts: webservers
become: yes
roles:
- role: webserver
vars:
nginx_port: 8080
document_root: /var/www/myapp
# roles/app/meta/main.yml
---
dependencies:
- role: common
- role: nginx
vars:
nginx_port: 8080
- role: postgresql
when: database_enabled | default(false)
{# templates/app.conf.j2 #}
# {{ app_name }} 的应用配置
# 由 Ansible 于 {{ ansible_date_time.iso8601 }} 生成
[server]
host = {{ ansible_default_ipv4.address }}
port = {{ app_port }}
workers = {{ ansible_processor_vcpus }}
[database]
host = {{ db_host }}
port = {{ db_port }}
name = {{ db_name }}
user = {{ db_user }}
password = {{ db_password }}
[cache]
enabled = {{ cache_enabled | default(true) | lower }}
{% if cache_enabled | default(true) %}
backend = redis
redis_host = {{ redis_host }}
redis_port = {{ redis_port }}
{% endif %}
[features]
{% for feature, enabled in features.items() %}
{{ feature }} = {{ enabled | lower }}
{% endfor %}
{% if environment == 'production' %}
[production]
debug = false
log_level = warning
{% else %}
[development]
debug = true
log_level = debug
{% endif %}
---
- name: 变量示例
hosts: all
vars:
app_name: myapp
app_version: 1.0.0
vars_files:
- vars/common.yml
- "vars/{{ environment }}.yml"
tasks:
- name: 从文件加载变量
include_vars:
file: "vars/{{ ansible_distribution }}.yml"
- name: 设置事实
set_fact:
full_app_name: "{{ app_name }}-{{ app_version }}"
- name: 注册输出
command: hostname
register: hostname_output
- name: 使用已注册变量
debug:
msg: "主机名是 {{ hostname_output.stdout }}"
- name: 访问事实
debug:
msg: |
操作系统: {{ ansible_distribution }} {{ ansible_distribution_version }}
内核: {{ ansible_kernel }}
CPU: {{ ansible_processor_vcpus }} 核心
内存: {{ ansible_memtotal_mb }} MB
IP: {{ ansible_default_ipv4.address }}
---
- name: 错误处理示例
hosts: all
tasks:
- name: 可能失败的任务
command: /bin/false
ignore_errors: yes
- name: 带有自定义错误处理的任务
block:
- name: 尝试启动服务
systemd:
name: myapp
state: started
rescue:
- name: 记录错误
debug:
msg: "启动 myapp 失败"
- name: 尝试替代方案
systemd:
name: myapp-fallback
state: started
always:
- name: 此任务始终运行
debug:
msg: "清理任务"
- name: 断言条件
assert:
that:
- ansible_memtotal_mb >= 2048
- ansible_processor_vcpus >= 2
fail_msg: "服务器不满足最低要求"
- name: 满足条件时失败
fail:
msg: "生产环境部署需要版本标签"
when:
- environment == 'production'
- app_version == 'latest'
- name: 满足条件时标记为已更改
command: /usr/local/bin/check_status.sh
register: result
changed_when: "'updated' in result.stdout"
failed_when: result.rc not in [0, 2]
# 创建加密文件
ansible-vault create secrets.yml
# 编辑加密文件
ansible-vault edit secrets.yml
# 加密现有文件
ansible-vault encrypt vars/production.yml
# 解密文件
ansible-vault decrypt vars/production.yml
# 查看加密文件
ansible-vault view secrets.yml
# 重新设置密钥(更改密码)
ansible-vault rekey secrets.yml
# secrets.yml (已加密)
---
db_password: supersecret
api_key: abc123xyz
ssl_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
# 在 playbook 中使用
---
- name: 使用密钥部署
hosts: production
vars_files:
- secrets.yml
tasks:
- name: 配置数据库
template:
src: db.conf.j2
dest: /etc/db.conf
no_log: yes # 不记录敏感数据
# 使用 Vault 密码运行 playbook
ansible-playbook playbook.yml --ask-vault-pass
# 使用密码文件
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass
# 使用多个 Vault ID
ansible-playbook playbook.yml --vault-id prod@prompt --vault-id dev@~/.vault_dev
ansible-project/
├── ansible.cfg
├── inventory/
│ ├── production/
│ │ ├── hosts.yml
│ │ └── group_vars/
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
├── playbooks/
│ ├── site.yml
│ ├── webservers.yml
│ └── databases.yml
├── roles/
│ ├── common/
│ ├── nginx/
│ └── postgresql/
├── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── host_vars/
└── files/
# ❌ 非幂等
- name: 向文件添加行
shell: echo "server {{ ansible_hostname }}" >> /etc/hosts
# ✅ 幂等
- name: 向文件添加行
lineinfile:
path: /etc/hosts
line: "server {{ ansible_hostname }}"
state: present
使用 strategy: free 以加速执行
在 ansible.cfg 中启用流水线
对长时间运行的任务使用 async
不需要时禁用事实收集
使用 serial 进行滚动更新
[defaults] forks = 20 host_key_checking = False pipelining = True gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts fact_caching_timeout = 86400
name: 快速部署 hosts: webservers strategy: free gather_facts: no serial: 5 # 每次部署到 5 台主机
tasks:
name: 长时间运行的任务 command: /usr/local/bin/build.sh async: 3600 poll: 0 register: build_job
name: 检查构建状态 async_status: jid: "{{ build_job.ansible_job_id }}" register: job_result until: job_result.finished retries: 60 delay: 30
no_log: yesbecome# 安装 molecule
pip install molecule molecule-docker
# 初始化 molecule
cd roles/myapp
molecule init scenario
# 运行测试
molecule test
# 测试工作流
molecule create # 创建测试实例
molecule converge # 运行 playbook
molecule verify # 运行测试
molecule destroy # 清理
# molecule/default/molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu
image: geerlingguy/docker-ubuntu2004-ansible
pre_build_image: yes
provisioner:
name: ansible
verifier:
name: ansible
❌ 不使用角色:将代码组织到可复用的角色中 ❌ 到处使用 shell 命令:尽可能使用模块 ❌ 硬编码值:使用变量 ❌ 没有错误处理:使用 block、rescue、always ❌ 以明文存储密钥:使用 Ansible Vault ❌ 不进行测试:使用 molecule 进行角色测试 ❌ 忽视幂等性:任务应可安全地多次运行 ❌ 复杂的 playbook:拆分为更小、更专注的 playbook
每周安装次数
143
代码仓库
GitHub 星标数
11
首次出现
2026 年 1 月 24 日
安全审计
安装于
opencode130
codex124
gemini-cli121
github-copilot115
cursor114
kimi-cli111
Expert guidance for Ansible - configuration management, application deployment, and IT automation using declarative YAML playbooks.
# Using pip
pip install ansible
# Using apt (Ubuntu/Debian)
sudo apt update
sudo apt install ansible
# Using yum (RHEL/CentOS)
sudo yum install ansible
# Verify installation
ansible --version
# inventory/hosts
[webservers]
web1.example.com
web2.example.com ansible_host=192.168.1.10
[databases]
db1.example.com ansible_user=dbadmin
db2.example.com
[production:children]
webservers
databases
[production:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_connection=ssh
# inventory/hosts.yml
all:
children:
webservers:
hosts:
web1.example.com:
web2.example.com:
ansible_host: 192.168.1.10
databases:
hosts:
db1.example.com:
ansible_user: dbadmin
db2.example.com:
production:
children:
webservers:
databases:
vars:
ansible_python_interpreter: /usr/bin/python3
ansible_connection: ssh
#!/usr/bin/env python3
# inventory/aws_ec2.py
import json
import boto3
def get_inventory():
ec2 = boto3.client('ec2', region_name='us-east-1')
response = ec2.describe_instances(Filters=[
{'Name': 'instance-state-name', 'Values': ['running']}
])
inventory = {
'_meta': {'hostvars': {}},
'all': {'hosts': []},
'webservers': {'hosts': []},
'databases': {'hosts': []},
}
for reservation in response['Reservations']:
for instance in reservation['Instances']:
ip = instance['PrivateIpAddress']
tags = {tag['Key']: tag['Value'] for tag in instance.get('Tags', [])}
inventory['all']['hosts'].append(ip)
inventory['_meta']['hostvars'][ip] = {
'ansible_host': ip,
'instance_id': instance['InstanceId'],
'instance_type': instance['InstanceType'],
}
# Group by role tag
role = tags.get('Role', '')
if role in inventory:
inventory[role]['hosts'].append(ip)
return inventory
if __name__ == '__main__':
print(json.dumps(get_inventory(), indent=2))
# playbooks/webserver.yml
---
- name: Configure web servers
hosts: webservers
become: yes
vars:
app_port: 8080
app_user: webapp
tasks:
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Start and enable nginx
systemd:
name: nginx
state: started
enabled: yes
- name: Copy nginx configuration
template:
src: templates/nginx.conf.j2
dest: /etc/nginx/sites-available/default
mode: '0644'
notify: Reload nginx
- name: Create application user
user:
name: "{{ app_user }}"
state: present
shell: /bin/bash
handlers:
- name: Reload nginx
systemd:
name: nginx
state: reloaded
# playbooks/deploy-app.yml
---
- name: Deploy application
hosts: webservers
become: yes
vars:
app_name: myapp
app_version: "{{ version | default('latest') }}"
app_port: 8080
deploy_user: deployer
pre_tasks:
- name: Check if required variables are defined
assert:
that:
- app_name is defined
- app_version is defined
fail_msg: "Required variables are not defined"
tasks:
- name: Create deployment directory
file:
path: "/opt/{{ app_name }}"
state: directory
owner: "{{ deploy_user }}"
group: "{{ deploy_user }}"
mode: '0755'
- name: Download application artifact
get_url:
url: "https://artifacts.example.com/{{ app_name }}/{{ app_version }}/{{ app_name }}.jar"
dest: "/opt/{{ app_name }}/{{ app_name }}-{{ app_version }}.jar"
mode: '0644'
register: download_result
- name: Create systemd service
template:
src: templates/app.service.j2
dest: "/etc/systemd/system/{{ app_name }}.service"
mode: '0644'
notify:
- Reload systemd
- Restart application
- name: Enable application service
systemd:
name: "{{ app_name }}"
enabled: yes
- name: Wait for application to start
wait_for:
port: "{{ app_port }}"
delay: 5
timeout: 60
when: download_result.changed
- name: Check application health
uri:
url: "http://localhost:{{ app_port }}/health"
status_code: 200
retries: 3
delay: 5
post_tasks:
- name: Clean up old versions
shell: |
cd /opt/{{ app_name }}
ls -t {{ app_name }}-*.jar | tail -n +4 | xargs -r rm
args:
executable: /bin/bash
handlers:
- name: Reload systemd
systemd:
daemon_reload: yes
- name: Restart application
systemd:
name: "{{ app_name }}"
state: restarted
---
- name: Conditional and loop examples
hosts: all
tasks:
- name: Install package (Debian)
apt:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
when: ansible_os_family == "Debian"
- name: Install package (RedHat)
yum:
name: "{{ item }}"
state: present
loop:
- nginx
- postgresql
- redis
when: ansible_os_family == "RedHat"
- name: Create users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'alice', groups: 'wheel' }
- { name: 'bob', groups: 'users' }
- { name: 'charlie', groups: 'developers' }
- name: Configure services
systemd:
name: "{{ item.name }}"
state: "{{ item.state }}"
enabled: "{{ item.enabled }}"
loop:
- { name: 'nginx', state: 'started', enabled: yes }
- { name: 'postgresql', state: 'started', enabled: yes }
- { name: 'redis', state: 'started', enabled: yes }
- name: Set fact based on condition
set_fact:
environment_type: "{{ 'production' if inventory_hostname in groups['production'] else 'development' }}"
- name: Debug conditional
debug:
msg: "This is a {{ environment_type }} server"
roles/
└── webserver/
├── defaults/
│ └── main.yml # Default variables
├── files/
│ └── app.conf # Static files
├── handlers/
│ └── main.yml # Handlers
├── meta/
│ └── main.yml # Role metadata and dependencies
├── tasks/
│ └── main.yml # Main task list
├── templates/
│ └── nginx.conf.j2 # Jinja2 templates
├── tests/
│ └── test.yml # Role tests
└── vars/
└── main.yml # Role variables
# roles/webserver/defaults/main.yml
---
nginx_port: 80
nginx_user: www-data
document_root: /var/www/html
# roles/webserver/tasks/main.yml
---
- name: Install nginx
apt:
name: nginx
state: present
update_cache: yes
- name: Copy nginx configuration
template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
mode: '0644'
notify: Restart nginx
- name: Create document root
file:
path: "{{ document_root }}"
state: directory
owner: "{{ nginx_user }}"
mode: '0755'
- name: Start nginx
systemd:
name: nginx
state: started
enabled: yes
# roles/webserver/handlers/main.yml
---
- name: Restart nginx
systemd:
name: nginx
state: restarted
# roles/webserver/templates/nginx.conf.j2
user {{ nginx_user }};
worker_processes auto;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen {{ nginx_port }};
server_name {{ ansible_hostname }};
root {{ document_root }};
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
}
# Use role in playbook
---
- name: Configure web servers
hosts: webservers
become: yes
roles:
- role: webserver
vars:
nginx_port: 8080
document_root: /var/www/myapp
# roles/app/meta/main.yml
---
dependencies:
- role: common
- role: nginx
vars:
nginx_port: 8080
- role: postgresql
when: database_enabled | default(false)
{# templates/app.conf.j2 #}
# Application configuration for {{ app_name }}
# Generated by Ansible on {{ ansible_date_time.iso8601 }}
[server]
host = {{ ansible_default_ipv4.address }}
port = {{ app_port }}
workers = {{ ansible_processor_vcpus }}
[database]
host = {{ db_host }}
port = {{ db_port }}
name = {{ db_name }}
user = {{ db_user }}
password = {{ db_password }}
[cache]
enabled = {{ cache_enabled | default(true) | lower }}
{% if cache_enabled | default(true) %}
backend = redis
redis_host = {{ redis_host }}
redis_port = {{ redis_port }}
{% endif %}
[features]
{% for feature, enabled in features.items() %}
{{ feature }} = {{ enabled | lower }}
{% endfor %}
{% if environment == 'production' %}
[production]
debug = false
log_level = warning
{% else %}
[development]
debug = true
log_level = debug
{% endif %}
---
- name: Variable examples
hosts: all
vars:
app_name: myapp
app_version: 1.0.0
vars_files:
- vars/common.yml
- "vars/{{ environment }}.yml"
tasks:
- name: Load variables from file
include_vars:
file: "vars/{{ ansible_distribution }}.yml"
- name: Set fact
set_fact:
full_app_name: "{{ app_name }}-{{ app_version }}"
- name: Register output
command: hostname
register: hostname_output
- name: Use registered variable
debug:
msg: "Hostname is {{ hostname_output.stdout }}"
- name: Access facts
debug:
msg: |
OS: {{ ansible_distribution }} {{ ansible_distribution_version }}
Kernel: {{ ansible_kernel }}
CPU: {{ ansible_processor_vcpus }} cores
Memory: {{ ansible_memtotal_mb }} MB
IP: {{ ansible_default_ipv4.address }}
---
- name: Error handling examples
hosts: all
tasks:
- name: Task that might fail
command: /bin/false
ignore_errors: yes
- name: Task with custom error handling
block:
- name: Try to start service
systemd:
name: myapp
state: started
rescue:
- name: Log error
debug:
msg: "Failed to start myapp"
- name: Try alternative
systemd:
name: myapp-fallback
state: started
always:
- name: This always runs
debug:
msg: "Cleanup task"
- name: Assert condition
assert:
that:
- ansible_memtotal_mb >= 2048
- ansible_processor_vcpus >= 2
fail_msg: "Server does not meet minimum requirements"
- name: Fail when condition
fail:
msg: "Production deployment requires version tag"
when:
- environment == 'production'
- app_version == 'latest'
- name: Changed when condition
command: /usr/local/bin/check_status.sh
register: result
changed_when: "'updated' in result.stdout"
failed_when: result.rc not in [0, 2]
# Create encrypted file
ansible-vault create secrets.yml
# Edit encrypted file
ansible-vault edit secrets.yml
# Encrypt existing file
ansible-vault encrypt vars/production.yml
# Decrypt file
ansible-vault decrypt vars/production.yml
# View encrypted file
ansible-vault view secrets.yml
# Rekey (change password)
ansible-vault rekey secrets.yml
# secrets.yml (encrypted)
---
db_password: supersecret
api_key: abc123xyz
ssl_key: |
-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----
# Use in playbook
---
- name: Deploy with secrets
hosts: production
vars_files:
- secrets.yml
tasks:
- name: Configure database
template:
src: db.conf.j2
dest: /etc/db.conf
no_log: yes # Don't log sensitive data
# Run playbook with vault password
ansible-playbook playbook.yml --ask-vault-pass
# Use password file
ansible-playbook playbook.yml --vault-password-file ~/.vault_pass
# Use multiple vault IDs
ansible-playbook playbook.yml --vault-id prod@prompt --vault-id dev@~/.vault_dev
ansible-project/
├── ansible.cfg
├── inventory/
│ ├── production/
│ │ ├── hosts.yml
│ │ └── group_vars/
│ └── staging/
│ ├── hosts.yml
│ └── group_vars/
├── playbooks/
│ ├── site.yml
│ ├── webservers.yml
│ └── databases.yml
├── roles/
│ ├── common/
│ ├── nginx/
│ └── postgresql/
├── group_vars/
│ ├── all.yml
│ └── webservers.yml
├── host_vars/
└── files/
# ❌ Not idempotent
- name: Add line to file
shell: echo "server {{ ansible_hostname }}" >> /etc/hosts
# ✅ Idempotent
- name: Add line to file
lineinfile:
path: /etc/hosts
line: "server {{ ansible_hostname }}"
state: present
Use strategy: free for faster execution
Enable pipelining in ansible.cfg
Use async for long-running tasks
Disable fact gathering when not needed
Use serial for rolling updates
[defaults] forks = 20 host_key_checking = False pipelining = True gathering = smart fact_caching = jsonfile fact_caching_connection = /tmp/ansible_facts fact_caching_timeout = 86400
name: Fast deployment hosts: webservers strategy: free gather_facts: no serial: 5 # Deploy to 5 hosts at a time
tasks:
name: Long running task command: /usr/local/bin/build.sh async: 3600 poll: 0 register: build_job
name: Check build status async_status: jid: "{{ build_job.ansible_job_id }}" register: job_result until: job_result.finished retries: 60 delay: 30
no_log: yes for sensitive tasksbecome sparingly# Install molecule
pip install molecule molecule-docker
# Initialize molecule
cd roles/myapp
molecule init scenario
# Run tests
molecule test
# Test workflow
molecule create # Create test instances
molecule converge # Run playbook
molecule verify # Run tests
molecule destroy # Cleanup
# molecule/default/molecule.yml
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: ubuntu
image: geerlingguy/docker-ubuntu2004-ansible
pre_build_image: yes
provisioner:
name: ansible
verifier:
name: ansible
❌ Not using roles : Organize code in reusable roles ❌ Shell commands everywhere : Use modules when available ❌ Hardcoded values : Use variables ❌ No error handling : Use blocks, rescue, always ❌ Storing secrets in plaintext : Use Ansible Vault ❌ Not testing : Use molecule for role testing ❌ Ignoring idempotency : Tasks should be safe to run multiple times ❌ Complex playbooks : Break into smaller, focused playbooks
Weekly Installs
143
Repository
GitHub Stars
11
First Seen
Jan 24, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykWarn
Installed on
opencode130
codex124
gemini-cli121
github-copilot115
cursor114
kimi-cli111
Azure Data Explorer (Kusto) 查询技能:KQL数据分析、日志遥测与时间序列处理
130,600 周安装