Automating APT updates with Ansible
Streamline Your Server Management: Automate Debian and Ubuntu Updates with Ansible
A major part of DevOps and programming in general is automating basic tasks. A common task to automate is package updates. If you have a ton of servers (perhaps you’re using Proxmox?) that need to be updated regularly then you can use a tool like Ansible! Ansible is a popular Infrastructure as Code (IaC) tool that can configure and streamline tasks on your servers.
This guide will be a simple introduction to Ansible and using it to automate updates on your remote systems that use the apt package manager.
Prerequisites
Install Ansible
The first prerequisite is obviously installing Ansible. Under the hood, it just uses SSH to execute remote commands. That means that your servers don’t need Ansible installed. On my NixOS machine (My daily driver currently), I installed Ansible like this:
# configuration.nix
environment.systemPackages = with pkgs; {
ansible
};
If you are using Debian or something similar for your main computer, you can use pip
to install Ansible (Docs):
$ python3 -m pip -V #check if pip is installed
$ python3 -m pip install --user ansible #install ansible for user
Make sure the servers have Python 3+
Most Debian and Ubuntu operating systems have Python installed already. You can double-check the installation using this command:
$ python3 -V
SSH keys on each server
When accessing a remote server, the best practice is to use SSH keys. Not only is it more secure, but it also doesn’t require a password when logging in.
If you don’t already have SSH keys on your server, you can read this post where I explained how to set it up.
How to remotely log into a server using SSH
If you’re a developer, there’s a good chance you have run into SSH. Secure Shell, also known as SSH, securely connects you to a remote computer. It is most commonly used among administrators to access Linux servers. Connecting The command to start a connection is pretty simple. It's just
Creating an Ansible inventory
Before we can execute tasks on multiple servers at once, Ansible needs to know where it’s sending these tasks. So let's create an inventory file. You can name it whatever and put it anywhere you wish. I just named mine hosts
and put it inside a folder labeled Ansible
. I also put my playbooks in this folder.
The hosts
file in this post is formatted for the ini
format, but can also be written in yaml
.
Opening the inventory file in your favorite text editor, create a group name like this:
[servers]
<server_ip1>
<server_hostname>
The group name can be whatever you want. As of writing, I'm only using Ansible to automate 2 servers, both running Debian cloud, but I still named the group [debian]
in case I want to add non-Debian servers later down the road.
Under the group name, you can list the servers you want to connect to. This can either be the server IP or the hostname. If you have an SSH config file for the servers, you can also use those alias names.
Testing the connections
Once you have the inventory file created and saved you can ping the servers using Ansible to test out the connection. The command to do that is:
ansible -i <path_to_inventory_file> -m ping all
This will return JSON that confirms if the servers were reached. If you have multiple groups and only want to ping one then you can replace all
in the command above with the group name.
Creating a Playbook
The playbook is the file that defines the tasks to execute on our remote servers. It is made in YAML format. Create a new subfolder in theAnsible
folder you made earlier. I called it playbooks
because it’s easy to remember.
Then create a new file called apt.yml
and open it. Let’s define a name for the playbook, and the host group(s) it connects to, and then tell it to become
root.
- name: "Update APT packages"
hosts: "debian"
become: yes
tasks:
...
If you want this playbook to access all hosts, you can use a wild card ( "*"
) in the hosts:
section.
Under the tasks:
section is where we define our… well, tasks. This example will only define one, but Ansible’s real power shines when you can add many.
Add this to your playbook:
tasks:
- name: apt
apt:
update_cache: yes
upgrade: yes
Each task includes a name
for clarity and the module-specific parameters ( update_cache
and upgrade
) to specify what should be done.
Running the Playbook
Now that you’ve created your playbook, you can execute it using the ansible-playbook
command:
ansible-playbook <path/to/playbook> -i <path/to/inventory> --user <user>
Make sure to replace <user>
with the SSH username. This flag might not be necessary if you have the username defined in your SSH config or inventory file. You will also need to define the inventory file using the -i
flag.
Running the command will show an output of Ansible “Gathering Facts” (checking the server connections), executing the tasks on each server, and then giving a recap.
I hope this post helped you with your Ansible journey! I am relatively new to Ansible, so portions of this article may be incorrect or not the best practice. I will continue to learn about this tool and will write about more advanced concepts in the future as I understand them. Happy Automating!