Show HN: Welder – set up your Linux server with plain shell scripts
github.com
github.com
Bash is great for a quick setup or a one-off instance. However it requires discipline for anything more. You are also dealing with the underlying OS yourself (e.g., Nginx is packaged and configured differently in Ubuntu, Debian, Cent OS & Arch; networking is configured differently in Ubuntu depending on whether systemd is installed, etc.).
methinks each of these must in fact call the shell to get things done or least system(3).
if they are calling execve then i would be more interested.
i would also be interested in ansible, chef, puppet if i knew the scripting languages they are written in or wanted to learn them. but other languages interest me more.
as a hobbyist, what i would like to see is a hosting provider that will boot fs images (including bootloader) that user builds on users own computer. i.e., provider gives exact specs of machine and network details. user builds and sends fs image to provider and provider boots from it on some bare metal in a datacenter.
no "host" or "guest". no virtual server. no provider software. if something software-related does not work, it is user's responsibility because it is all user's software. user can send an updated fs image.
anyone know if this exists? the service wanted is barebones: a computer in a datacenter that has an internet connection and someone to boot it from user fs image. cost not an issue.
This is actually somewhat possible with linode. It's not easy to do but it's possible.
https://www.linode.com/docs/platform/disk-images/migrating-a...
I had so many problems with this, because not all possibilities are tested on all distributions on all architectures with all libc's and compiler combinations. Much is implicit compared to Nix where only the kernel is implicit.
With some sane level of standardization (lets say less than 6 combinations) it's easy enough to test all and fix up the discrepencies.
The more declaritive you are, and the less you assume about the environment, the better this will work.
Ie. if you need a package, always install it. On some distros it may be there by default, but you'll run into issues if it's not. The good thing about being declaritive is that there's no harm in checking.
Much of the time, virtualization is just a way to give you control over the whole machine. If virtualization is thin, you don't lose a lot of performance.
It shouldn't be hard to make a Xen-backed VM administration interface. Then you can upload your MirageOS images (that you have tested on your local Linux, because MirageOS does that too) and it would work.
You can't get rid of virtualization and still have it remotely configurable. How are you going to reset configuration of a machine if you destroyed the bootloader of the ring-0 operating system?
some configuration is fixed, static. to change it one needs to change the image. this is intentional. hobbyist user wants this.
bootloader is on removable media user sends to provider. user is not using any provider software. user is paying for dedicated server and internet connection. that is all.
do not use linux, mirageos. do not need to. have rump. user can make own xen guest kernels and xen host kernels. anyway, this is tangent, irrelevant. user does not need virtualization necessarily and in any case not virtualization provided by third party.
simple requirements: want dedicated bare metal server. want hardware and internet connection. do not need/want provider software. will pay more for this.
https://github.com/mattly/bork
and here is an example from their README:
ok brew # presence and updatedness of Homebrew
ok brew git # presence and updatedness of Homebrew git package
ok directory $HOME/code # presence of the ~/code directory
ok github $HOME/code/dotfiles mattly/dotfiles # presence, drift of git repository in ~/code/dotfiles
cd $HOME
for file in $HOME/code/dotfiles/configs/*
do # for each file in ~/code/dotfiles/configs,
ok symlink ".$(basename $file)" $file # presense of a symlink to file in ~ with a leading dot
doneI replaced a home grown, written by someone else, bash configuration management tool with Salt. The difference was huge.
Configuration management tools give you built-in logging, state checking, return codes, template libraries, and access to very mature models to access things like the AWS api.
I realize people don't like the steep learning curve, but there is a reason for it.
Dynamic inventory scripts + ansible-playbook -k -u root ....
can do the same thing for bootstrapping.
How is this an advantage over that?
- name: Bootstrap Ansible
hosts: all
gather_facts: False
tasks:
- name: Install Python 2
raw: test -e /usr/bin/python || (sudo apt -y update && sudo apt install -y python-minimal)How is Welder different from Ansible, except bash vs python?
The tools in this space feel like very thick abstractions on top of commands and configs you have to understand any way, to get the results you want. The console output Ansible produces is also truly horrible.
Instead, I now maintain a single shell script for our servers. It's maybe a couple hundred lines, half of it heredocs containing small config snippets.
I will definitely be looking at this tool later.
It does, thats kind of the point in my mind. All I have to learn is the reasonably thin configuration management on top of normal stuff.
http://tldp.org/LDP/abs/html/string-manipulation.html
See the section under Substring Replacement.
That's a lot harder to achieve with plain shell scripts, unless you're pretty disciplined about only performing mutations to your system that are themselves idempotent (like a package install).
Indeed. That's why I use Saltstack. I can do all I use Salt for without Salt. Except Idempotency
Due to taking over a project I had to deep dive into it pretty quickly and to me it feels like shell in yaml syntax.
Or with --check, before you make the change :)
https://ryaneschinger.com/blog/ensuring-command-module-task-...
But as long as you're careful about coupling operations like lineinfile with checks for the line already being there and so on, you can achieve it (and Ansible certainly makes this much easier than shells scripts do).
There are a few tricks that Ansible uses that are non-obvious uses of shell - For example, files should be replaced by copying the new version to the target directory, then unlinking the original file and linking in the new version in it's place, finally unlinking the temporary file. This functionality has been implemented in the 'install' utility in gnu and bsd coreutils since the 80s (though it's not in POSIX, so it's not exactly guaranteed; You'd be hard-pressed to find a machine outside of busybox docker images that does not support it)
I agree that modules like lineinfile are tricky and should be avoided (better to copy a full file), but it's hardly just as easy to shoot yourself than the equivalent sed command, in my opinion, if nothing else because they're more restricted.
It's not realistic to perform a multi-minute deploy (or have to be resetting VMs to snapshots) just to try out tweaks in your non-idempotent setup script.
I feel like there's a cadre of developers who used Bash, Perl, and Unix in the mid-90s - early naughties, to excellent effect, but have resisted learning anything else since, in the mistaken belief that these tools were appropriate solutions to all classes of problem.
And not to say that shell scripts are bad, just that the range of tasks for which they are best suited is far more restrictive then people seem to think. A friend surprised me by saying that Bash was an essential part of his genetics research, and after being initially shocked, the idea made rather a lot of sense: genetic data is semi-structured text, and much of his work involved transforming the output of one program to the input of another. Outside of such applications, I view the use of Bash as non-optimal at best.
https://github.com/CyberShadow/aconfmgr
It has a few crucial differences from typical configuration managers, though, as it allows transcribing the system state back into your configuration.
I completely agree with OP when Ansible is overkill for must cases, and even slower than a plain smart shell script.
For my solution, simple create a bash function:
function play ()
local remote=${2}
local script=${1}
local directory=$(dirname ${script})
tar cpf - ${directory}/ | ssh -t ${remote} "
tar xpf - -C /tmp &&
cd /tmp/${dirname} &&
bash /tmp/${script} &&
rm -rf /tmp/${dirname} "
}
and later just call it like. play provision/bootstrap.sh ubuntu@10.0.0.1
Where provision is a directory, and bootstrap.sh is the main shell script.I tried https://github.com/myplaceonline/posixcube and it has zero dependencies , just bash itself, and it is nice.
I wrote a little 'tarball compiler' framework in mostly PMake some time ago to "DevOps" like it's 19[89]9 ... basically it will build per-host file overlay trees, rdist them out to target hosts, and then optionally run user defined start/stop/restart hook scripts when needed.
https://github.com/ixcat/admmk/blob/master/doc/admmk.rst
unfortunately, though it will do per-host targets, I didn't get around to per-service targets.. should be feasable however.
Definitely a bit hairy, but hey, thats what quasi-functional symbolic makefile programming is all about my friends..
ps: if you think this is bad, try rewriting it in gnumake if that's even possible.. PMake! Woo!
Packer can generate base images and roles based on shell scripts and transferring files. Terraform manages the creation of infrastructure on clouds and can bootstrap instances with shell scripts as well.
[1] - https://terraform.io [2] - https://packer.io
ssh -t user@example.com "$(< ./my-setup-script.sh)" ssh -t user@example.com "$(cat ./my-setup-script.sh)"
I'll have to file this away myself![bash] https://www.gnu.org/software/bash/manual/html_node/Command-S...
[posix] http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3...
ssh -t user@example.com /bin/bash < my-setup-script.sh
That is, take the contents of the local file 'my-setup-script.sh' and run them as commands on example.com as the 'user' user (using SSH to authenticate the user & transport the commands).Oh, while transferring!
ssh -t user@example.org bash <( echo "function do_it() {"; cat my-setup-script.sh; echo -e "}\ndo_it" )
No argument limits to worry about, no quoting hassles.Looking at how you use this thing, I'm really not sure it would save me any time versus using Ansible.
Ansible is also declarative (in principle) while shell scripts are imperative, which is a bit of mind bender. Then, when you debug, you have to understand that Ansible is implemented by imperative code.
Bringing people up to speed on in-house tools can be a major hassle. Never mind the fact that popular tools like Ansible are battle-tested and most likely has more documentations and tutorials.
Ansible has some undisputed advantages (e.g. idempotence) and if I had to recommend Ansible vs my approach, I'd always recommend Ansible. But for my personal needs (single-server rails apps), I prefer shell scripts.
Which for my FreeBSD machines I have to run some bootstrap code that installs Python on it before I can run ansible against it.
Would be nice if salt-ssh or ansible allowed me to have some bootstrap code that ran if Python didn't exist on the target machine.
Given you generally have to know what you're trying to achieve in shell anyway, the shell versions are simpler, if less robust. For example,
sudo apt update && sudo apt install nginx
is easier than become: True
tasks:
- name: install nginx for great justice
apt:
name: nginx
update_cache: yes
state: latest
There are also some edge cases where shell is better than ansible; some parameters are missing from some modules, meaning shell is more flexible; or if you want to read a command's STDOUT, it's a pain in Ansible.