The best thing about is that it's agentless, meaning it doesn't require anything running on your target instances, before provisioning them. Good old SSH is all you need.
Before switching to Ansible, I was using Puppet. When compared, Ansible just makes everything work like a breeze. No more do I have to figure out how to make the target instances communicate with my Puppetmaster *before* you can do any kind of provisioning. With Ansible your instances are provisionable from the get-go.
Other things I like about it:
- Ad-Hoc commands
- Ansible Galaxy, especially how you can retrieve roles either from the public repositories or from your private SCM repositories.
- Ansible core has a task for almost any kind of work
- Works well with CI tools and it is beneficial to add the playbooks to your deployment pipeline, so the environments are provisioned each time code is committed.
- The tasks are ideally idempotent, so it won't redo the changes if everything looks okay on the target instance. (The reason why I say 'ideally' is because it is possible for you to make tasks that are not idempotent. But it is something you should avoid.)
YAML-only syntax might not always be the most customizable. Also it has most of the *magic* running out of sight, so you have to read through the Ansible source code on purpose, if you want to know what it actually does.
Main problem I've solved is keeping the test, dev and production environments identical.