Automation is the part of DevOps that actually earns the title. Day 6 was two of the most everyday automation tasks there are, and both had a trap sitting in plain sight.
One Linux task, one AWS task. Schedule a recurring job with cron, and launch an EC2 instance from the AWS CLI. The tasks come from the KodeKloud Engineer platform if you want the same lab to work through.
Cron: five fields, one rule that trips everyone
Cron is the scheduler that has quietly run Linux automation for decades. You hand it a job and a schedule, and its daemon, crond, wakes up every minute to check whether anything is due. If that daemon is not running, nothing fires, so the first move is making sure it is installed and enabled.
# Become root
sudo su -
# Install the cron daemon if it is missing
yum install cronie -y
# Enable it at boot, start it now, and confirm it is alive
systemctl enable crond.service
systemctl start crond.service
systemctl status crond.service
cronie is the package name on RHEL-family distros. enable makes the service survive a reboot, start brings it up right now, and status is how you confirm it is actually running instead of assuming it is. Now edit the crontab:
# Edit the current user's crontab
crontab -e
# minute hour day-of-month month day-of-week command
0 2 * * * /path/to/script.sh
# List what is currently scheduled
crontab -l
That line runs the script every day at 2am. The five fields, in order, are minute, hour, day of month, month, and day of week:
- minute: 0 to 59
- hour: 0 to 23
- day of month: 1 to 31
- month: 1 to 12
- day of week: 0 to 7, where both 0 and 7 mean Sunday
Here is the rule that quietly breaks schedules. When you set both the day-of-month field and the day-of-week field to something other than a star, cron treats them as OR, not AND. So 0 0 13 * 5 does not mean midnight on Friday the 13th. It means midnight on every 13th of the month, and also every Friday, whichever lands first. If you actually want the AND, you restrict one field in cron and check the other one inside your script.
Two more things bite people here.
Cron does not run with your shell environment. It uses a bare, minimal PATH and never reads your .bashrc or profile. A command that runs fine in your terminal can fail silently under cron because it cannot find the binary. Use absolute paths, both to your script and to anything the script calls.
Cron also says nothing when a job fails. By default, it tries to email the output to the local user, which on most boxes goes precisely nowhere. Redirect the output yourself so you have a trail to read:
# Capture normal output and errors so failures are visible
0 2 * * * /path/to/script.sh >> /var/log/myjob.log 2>&1
Launching EC2: gather first, launch once
The AWS task looks like a single run-instances command, but the command is the easy part. It fails the instant you feed it an argument it does not have, so the real work is gathering four things first: an AMI ID, a security group ID, a subnet ID, and a key pair.
# List the 5 newest Amazon-owned AMIs in the region
aws ec2 describe-images \
--owners amazon \
--region us-east-1 \
--query 'reverse(sort_by(Images,&CreationDate))[:5].{id:ImageId,date:CreationDate}' \
--output table
AMI IDs are region-specific, and they change often as Amazon publishes new images, so never hardcode one you found in a blog post, this one included. Look up a current ID in your own region every time. Next, find a security group and a subnet to launch into:
# The firewall (security group) and the network placement (subnet)
aws ec2 describe-security-groups
aws ec2 describe-subnets
The security group is the instance's firewall, and the subnet decides which VPC and availability zone it lands in. You need one ID from each. Then create the key pair, and this is the step to slow down on:
# Create a key pair and save the private key locally
aws ec2 create-key-pair \
--key-name my-key \
--query 'KeyMaterial' \
--output text > my-key.pem
# Lock the permissions down
chmod 400 my-key.pem
AWS shows you the private key exactly once, at creation. There is no re-download and no recovery. Lose that .pem and the key pair is dead weight, you delete it and generate a new one. The chmod 400 is not optional either, SSH refuses to use a private key that other users on the box could read. Now launch, feeding in everything you gathered:
# Launch the instance
aws ec2 run-instances \
--image-id ami-xxxxxxxxxxxx \
--count 1 \
--instance-type t2.micro \
--key-name my-key \
--security-group-ids sg-xxxxxxxxxx \
--subnet-id subnet-xxxxxxxxxx \
--tag-specifications 'ResourceType=instance,Tags=[{Key=Name,Value=my-ec2}]'
Swap in the real AMI, security group, and subnet IDs you just looked up. t2.micro is the small, free-tier-friendly size, --count 1 launches a single instance, and the tag block names it so you are not squinting at raw instance IDs later. Then confirm it came up:
# Verify the instance state
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=my-ec2" \
--query 'Reservations[*].Instances[*].{Id:InstanceId,State:State.Name}'
Right after launch the state reads pending, then flips to running within a minute or so. That tag filter is exactly why tagging at launch pays off, you query by name instead of digging for an ID.
One thing the task does not mention, but your wallet will. A running instance bills until you stop or terminate it. When the lab is done, terminate it. Learning to launch is only half the skill, cleaning up is the other half.
The actual lesson
Both tasks reward the same habit, and it is not typing speed. Cron punishes you for assuming the schedule means what it looks like. EC2 punishes you for launching before you have gathered what it needs. The people who get burned are the ones who sprint to the final command and skip the boring prep and the fine print.
So the choice for Day 6. Would you rather memorise the run-instances line and hope the environment matches, or understand every argument well enough to fix it yourself when it doesn't?
Day 6 down. Ninety-four to go.
Top comments (0)