Replacing Ansible with salt-ssh
blog.hartwork.org
blog.hartwork.org
Major issues with Salt: lots and lots of bugs and quirks. I have had my fair share of those in Ansible over the years as well, but Salt is just not good enough for my taste. A strong NIH is perceived all over its design.
The biggest issue I see with ansible is the amount of discipline required to use it well. Junior staff will create non-idempotent plays. I don't really see that with salt, where shelling out is pretty rare (the benefit of NIH?).
I've used both Ansible and SaltStack a fair bit and would agree with the parent. In most cases, Ansible w/ Mitogen is the way to go.
SaltStack is really only sanely deployable in a Masterless setup. Also the real secret sauce of SaltStack that almost no one is using it for is its Event Bus & Reactor System to automate maintenance/incident runbooks. There's a ton of untapped potential there.
There's style guides, linting, commit checks...
It takes the "operator" concept to a very new level: You can tell it to react automatically and enlarge a disk in a machine due to space constrains, reschedule workloads according to load, configure a loadbalacner according to rules you write once, create resiliency rules, deploy new machines or containers...
It scales ridiculously, i have seen 30000 minions to a master.
Why you would use it via ssh other than bootstrapping is beyond me...
btw: you can run ansible via the salt bus transport = salstack in the ansible.cfg, be amazed.
Thank you for putting it more cleanly.
I don't necessarily always think that's the right thing to do though, but within limits, yes. It can do things you would otherwise have people respond manually to.
Putting out fires sucks.
- name: Pretend to install stuff.
debug: var=item
with_items: [git, httpd, vim]
when:
- "'all' in ansible_run_tags or item in ansible_run_tags"
- item not in ansible_skip_tags
tags: always
If you run without any tags it will install everything and if you specify --tags=git it will only install git and if you specify --skip-tags=vim it will do the correct thing.Ref: https://docs.ansible.com/ansible/latest/reference_appendices...
And in the specific case of installing packages you can speed this process up dramatically with something like the following without having to use tags.
- name: Probe the host for installed packages.
package_facts:
- name: Install packages.
package: name={{ item }}
with_items: [git, httpd, vim]
when: item not in ansible_facts.packages
But this itself is really inefficient too because you're still calling the module for every package instead of calling the module once with all the packages. Older versions of Ansible did this automatically but it was super magic so it's probably better that it was removed. We can do it ourselves though. - name: Install packages.
package: name={{ to_install }}
vars:
packages: [git, httpd, vim]
to_install: "{{ packages | difference(ansible_facts.packages) | list }}"And how is an Ansible user supposed to know what's more efficient and what are the side effects of calling the packages with name={{item}} or a list variable? The documentation of ansible.builtin.package for one doesn't seem to supply any indication of it.
- name: Install packages.
package:
name: [git, httpd, vim] | difference(ansible_facts.packages) | list
This isn't something super specific to Ansible, it's the same story all over when libraries have a "bulk" or "batch" api so that you don't have to iterate over operations with lots of setup. The package/yum/apt/dnf modules happen to take lists as arguments since you can run "yum install a b c" faster than "for p in a b c; do yum install $p; done".Also I was confused by your claim that your second version was sped up dramatically although it is still using "with_items". Is this due to the use of facts instead of tags?
- name: Install packages
package: name={{ item }}
with_items: "{{ loooong_list_of_packages }}"
and most of the packages are already installed then you're spending most of the loop running the package module just for it to come back any say 'ok'. Hence why the author wanted to use tags to limit the run to specific packages.Rather than doing that you can run package_facts once to get a list of all the installed packages and skip all the module invocations you know won't be changed entirely. You can't do this in general because on a totally unknown system something exteranl might mess with packages between your fact gathering and the install but on your known systems this is almost always fine.
- hosts: all
tasks:
- name: Install distro packages
package:
name: "{{ item }}"
state: present
with_list: &packages
- git
- htop
tags: *packagesYou can tag playbooks and either run only the specified tags playbooks or skip those and run everything else.
From other podcast episodes I got to know that they at SaltStack are currently merging those many differently maintained SaltStack repos together to less repos, so it will make progress faster.
Disclaimer: I do not work at SaltStack. I just happily listen to their podcasts and I have used SaltStack for managing my servers.
https://www.educba.com/ansible-with_items/
Let me fix his code here: https://pastebin.com/PQDAnHiJ
I use with_items at least once a day in this manner.
- name: Install stuff.
package:
name: [git, httpd]You just had to supply the list as space separated. i.e.
package: {{ packages|join(' ') }}
or similarThen just point the module to the array, like in the linked example.
edit; Check out Spivak's solution in the comments below. Interrogate the host and find out what is needed, then apply the install- saves you all the time of getting back 'ok' results.
Please check the docs of with_list at https://docs.ansible.com/ansible/latest/user_guide/playbooks... .
salt-ssh $hostname state.highstate test=True
It can be used with just SSH and Chef Zero (no need for a Chef Server), and it's built with Ruby and Chef's DSL and not YAML.
It took me several years to not hate Chef's approach, though, compared to the ease of use of Ansible.
Migrating from Chef to XXX was an enormous pain. It’d be easier to migrate away from Ansible.
I use Ansible to build images and to configure (as in template configuration files in) newly provisioned systems after first boot-up and that's it.
Everything's end-to-end automated after I ship my code and I don't have to worry about it.
Systems don't get changed, they get rebuilt.
Chef is primarily a configuration management tool and I keep that separate from a distinctly provisioning tool like Terraform. Terraform is declarative rather than procedural like Chef and that's far preferred when trying to define what you have. Terraform & Ansible don't require me to run a master server or have agents on every machine either.
Use tools where they're strongest.
We used to use Chef years ago and replaced it with Ansible and Terraform and have zero regrets at 10^4 nodes. We also use Terraform for managing CloudFlare and all sorts of other providers. It has been a dream.
Ansible does less and less work as time goes on for us and as we've moved to semi-immutable infrastructure. If we need to change something about a system, we'd rather replace it.
I would love if we standardize in Packer, Ansible and Terraform. Luckily it seems like the devops world is standardizing in this stack ... there's very little you can't do in an elegant way using those 3 tools (only use the 3 if you need, a lot of shops only use Ansible for example)
All to get to slightly less downtime and faster deploys... idk. Hard to know if the months of work will be worth it.
If, that is, disk space is cheap enough that I don't have to normalize the filesystem (database-style) in order to function. That was a huge IF not so very long ago, which is why we are iterating on this again now.
I believe you're correct in that this is a fine stack of tools that can get anything done. I wish businesses would just use them.
- infrastructure
- configuration management
- image building
Although, frankly, the last two are solved much more elegantly through NixOS, so it ultimately could be:
- infrastructure configuration
- system configuration
I have recently done some scripting work on a single machine and used Ansible because it makes it so convenient to parse output, generate config files etc., mostly shell and jinja2
Is that valid use of Ansible or should I be ashamed and use something else?
If you eventually run into difficulties, sit down and understand why.
Once you've understood the cause of your problems, see whether the features you didn't take time to understand can alleviate them.
I very much don't like that it does the YAML-as-a-programming-language thing that's way too popular nowadays but when judiciously used, Ansible can be useful.
I really want something like Ansible with a real declarative programming language. Puppet is the closest nowadays to having a sane language, but it has its own issues.
if ! which sometool; then
install sometool
fi
That's an idempotent shell script, in all it's simple glory.