iverse.deviverse.dev

A fake CI/CD pipeline with cron

Jem Young6 min

tl;dr

Continuous integration is small merges and constant testing. Delivery and deployment differ by one thing: whether a person presses the button. And a two-line shell script plus cron makes a pipeline you shouldn't ship.

CI/CD looks like someone else's problem until you have more than one developer. One person on one server doesn't need it. A hundred people shipping features simultaneously do — otherwise it's everyone pushing whatever, one enormous merge on Friday, and hope.

Three terms, one real distinction

Commit, build and test bracketed as continuous integration, then a dashed gate before production marked with the question of whether a person is involved.
Delivery and deployment sound like synonyms. The gate is the entire difference.

Continuous integration is merging validated changes back to main as often as possible. Small atomic commits, not a branch you've held open for two weeks with fifty thousand lines in it. If you've never had to git bisect a production system, that's the thing CI is protecting you from.

Continuous delivery means changes are tested and ready to ship. Continuous deployment means they actually ship. Same pipeline; the difference is whether a human approves the last step — and that's a business decision. Healthcare software wants a person there. A marketing site doesn't.

Real setups use real tooling — Netflix runs on Spinnaker, which can stand up 500 correctly-configured, load-balanced clusters from a button. That is a Ferrari for mowing a lawn this size.

All you actually need is a stopwatch

cron runs a thing on an interval. That's it. Point it at a script that pulls from GitHub and you have a pipeline — a bad one, with no tests, which is why Jem calls it fake CI/CD and says plainly not to ship it.

The script

which bash                      # find the interpreter first
vi github.sh
#!/usr/bin/bash
cd /var/www/app
git pull --ff-only origin main
chmod 700 github.sh             # nothing is executable by default

Two lines of substance. #! — the hashbang — names the interpreter. --ff-only takes changes that fast-forward cleanly and refuses anything that would need a rebase, which is what you want from a script running unattended.

The schedule

Five asterisks labelled minute, hour, day of month, month and weekday, followed by the command.
`*/2` means every second one. A bare `2` means only at 2.
crontab -e
*/2 * * * * sh /var/www/app/github.sh 2>&1 | logger -t github.sh

That tail matters. Without it the output goes nowhere — the job runs, and you can't tell. 2>&1 merges standard error into standard out, logger writes it to syslog, and -t tags the entries so you can find them.

sudo tail -f /var/log/syslog

Now pushing to GitHub from your laptop lands on the server within two minutes, and you never open an editor over SSH again.

← all Full Stack Fundamentals, v3 posts