At three o’clock that morning, I was dealing with an unexpected online failure with my colleagues, where dozens of service nodes needed urgent configuration updates. Manual operation? Not realistic. Writing a temporary script? Too slow. At that moment, I remembered the Ansible + Python automation framework I had configured earlier. Within three minutes, all node configurations were synchronized, and the problem was resolved. At that moment, I truly felt the powerful force of operational automation.
Pain Points in Operations, I believe every practitioner can relate. As the scale of business expands, the number of servers managed has grown from a few to dozens, then to hundreds and even thousands, making manual operations overwhelming. I once experienced such a painful transformation period at an internet company: the operations team was exhausted every day dealing with various repetitive tasks, and the inconsistencies in server environments led to numerous issues, making troubleshooting feel like searching for a needle in a haystack.
The essence of the problem lies inscalable management and ensuring consistency. Traditional Shell scripts can solve some problems, but they quickly fall into the trap of being difficult to maintain, chaotic version management, and hard-to-track execution results. After exploring various solutions, we ultimately chose the combination of Ansible + Python, which is recognized as one of the best practices in the industry.
Ansible was born in 2012, and its design philosophy is heavily influenced by Unix philosophy – “do one thing and do it well.” Its agentless architecture (based on SSH communication) makes deployment exceptionally lightweight, declarative configuration (YAML formatted playbooks) makes automation processes easy to understand and maintain, while Python’s extensibility provides infinite possibilities for complex logic processing.
However, technology selection is just the first step; the real challenge lies in how to build an automation system suitable for the team. We have taken many detours, and the most typical mistake is to start by writing a large number of playbooks:
# Common beginner's mistake example
- name: Complex all-in-one playbook
hosts: all
tasks:
- name: Install packages
apt:
name: "{{ item }}"
state: present
with_items:
- nginx
- mysql-server
- redis-server
# Followed by dozens or hundreds of lines...
This seems to save time, but it actually lays landmines for future maintenance. Experience tells us that modularity and role separation are the correct paths:
# Improved modular structure
- import_playbook: roles/common/main.yml
- import_playbook: roles/nginx/main.yml
- import_playbook: roles/mysql/main.yml
Combining Python’s powerful capabilities, we built a configuration as code infrastructure. What I am most proud of is the dynamic asset management system, which can automatically classify and tag servers based on business labels:
def generate_dynamic_inventory():
"""Generate dynamic inventory based on CMDB information"""
inventory = {}
# Get server information from database or API
servers = get_servers_from_cmdb()
for server in servers:
# Dynamically group by tags
for tag in server.tags:
if tag not in inventory:
inventory[tag] = []
inventory[tag].append(server.ip)
# Write to a temporary file for Ansible use
with open('/tmp/dynamic_inventory.json', 'w') as f:
json.dump(inventory, f)
return '/tmp/dynamic_inventory.json'
# Example call
ansible_cmd = f"ansible-playbook -i {generate_dynamic_inventory()} deploy.yml"
This seemingly simple function executes tens of thousands of times in our environment daily, providing accurate target server information for business deployments. According to our performance tests, it controls execution time within 1.2 seconds when managing over 3000 nodes (test environment: 8 cores, 16GB RAM, Python 3.10).
As we accumulated experience, we gradually formed a set of best practices:
- Infrastructure Layering: Clearly separate configuration management, application deployment, monitoring, and alerting functions
- Idempotent Design: All operations must be repeatable without side effects
- Granularity Control: Split large tasks, set checkpoints for easy rollback and debugging
- Interface Standardization: Define a unified input and output format to enhance reusability
In last year’s technological transformation, we introduced deep integration of Ansible with CI/CD pipelines. As Martin Fowler said, “Infrastructure as code is not just automation; it is a mindset.” Every code commit triggers automated testing and deployment, minimizing the risks of “environment drift”.
Finally, I would like to share a few “pitfalls” we have encountered:
- Be cautious with the global configuration in
<span>ansible.cfg</span>
, as it may cause conflicts in multi-team environments - Beware of overly complex conditional logic in playbooks, as this is a blind spot for test coverage
- Avoid performing time-consuming operations in handlers, as this may lead to uncontrollable overall execution time
- Pay attention to variable precedence (host_vars > group_vars > defaults); non-standard definitions are the source of many errors
With the rise of cloud-native technologies, the combination of Ansible + Python is also continuously evolving. For me, regardless of how technology changes, automated thinking is the true core competitiveness. As I often tell new team members: the automation process built today in one hour may save you a hundred hours of repetitive labor and endless overtime pain in the future.
After all, true technological advancement is not about making us work overtime to solve problems, but about elegantly avoiding problems from occurring.