Welling Guzman's log

Infrequently learning journal and random notes

Discovering Ansible

2020-06-06

DigitalOcean hat some issue with their servers and had schedule a migration to move the droplet to another server, But my server a day after the migration was suppose to be done, still unreachable, no email from them saying if they had issue or not. I sent them a email about this couple of hours ago, and no reply. I shutdown my droplet and now I'm unable to boot it up.

One thing I know is that I have some services that I have to run manually and I knew this time will come, and I do not know which one are those. Great server management skills. It's just some small servers, and every year or so I say I don't need fancy configuration because I don't do this often, but now I would take this as an excuse to use a server management tool.

I would Ansible, less complex solution without the need to have a master server, and I can use my local environment to be the master server where all the changes will be made to a the server. I'm using Mac OSX and I installed ansible using pip

pip install --user ansible

Ansible when installed with pip --user is installed in your user directory, ~/Library/Python/<version>/bin instead of system directory. The user path should be added to your user $PATH.

export PATH="$PATH:~/Library/Python/2.7/bin"

By default ansible loads its configuration from /etc/ansible, I created a directory in my user directory and create a symlink to /etc/ansible. I'm following both ansible documentation and digital ocean guide. The other option is to use -i and specify the inventory path.

I found you don't need to create the symlink or anything there's a order in which ansible look for the the configuration, and you can set one in your home directory and change the inventory path there.

Changes can be made and used in a configuration file which will be searched for in the following order:

  • ANSIBLE_CONFIG (environment variable if set)
  • ansible.cfg (in the current directory)
  • ~/.ansible.cfg (in the home directory)
  • /etc/ansible/ansible.cfg

Source: Ansible docs

# ~/.ansible.cfg
inventory = ~/.ansible/hosts

I got an error while loading the configuration Error reading config file (/Users/<username>/.ansible.cfg): File contains no section headers., taking a look at an example configuration, I need to set the section header as [defaults]. Here's a config example

# ~/.ansible.cfg
[defaults]
inventory = ~/.ansible/hosts

Time to add the host into ~/.ansible/hosts

[servers]
wellingguzman ansible_host=<the-ip>

Now the server has an alias of wellingguzman that point to the host defined in ansible_host.

$ ansible-inventory --list

Now I can list the ansible inventory.

The host are defined, it's time to test them:

$ ansible all -a "df -h" -u root
Filesystem      Size  Used Avail Use% Mounted on
udev            3.9G     0  3.9G   0% /dev
tmpfs           798M  624K  798M   1% /run
/dev/vda1       155G  2.3G  153G   2% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/vda15      105M  3.6M  101M   4% /boot/efi
tmpfs           798M     0  798M   0% /run/user/0

2020-06-07

Copied the Digital Ocean init playbook, everything was working until I changed the default ssh port and wasn't able to connect my server anymore. I was locked out of my own server.

Luckily I'm able to log in through the web console in Digital Ocean, and solve the issue from there.

After checking the firewall, I learned that the OpenSSH is actually a profile name that translate to 22/tcp, which means the new port was blocked. I was mistaken, and OpenSSH is not a dynamic name for fetching the actual port from the sshd configuration.

I changed the port to the default one (22), on the server and updated the playbook to use the actual number and protocol instead of the profile name. I'm running the playbook one more time and see what happens.

# From this
- name: UFW - Allow SSH connections
  ufw:
    rule: allow
    name: OpenSSH

# To this
- name: UFW - Allow SSH connections
  ufw:
    rule: allow
    port: '{{ ssh_port | int }}'
    proto: tcp

I'm now able to run my playbook successfully now the server are working, and more important I know what are the commands that I used, so I can destroy this all the time I want and I will have my script to recreate them.

ansible-playbook playbook.yml -l wellingguzman -u root

My playbook, is almost identical as the playbook from digital ocean initial server playbook, the only difference here is that I changed the group name, and install nginx and node.

- name: Install Web Server Packages
  apt: name={{ item }} update_cache=yes state=latest
  loop: [ 'nginx' ]

# Install Node.js
- name: Add the NodeSource package signing key
  apt_key:
    url: 'https://deb.nodesource.com/gpgkey/nodesource.gpg.key'
    state: present
- name: Add the desired NodeSource repository
  apt_repository:
    repo: "deb https://deb.nodesource.com/node_{{ node_version }}.x {{ distro }} main"
    state: present
    update_cache: yes
- name: Install Node.js
  apt:
    name: nodejs
    state: present

There's still a lot to learn here, but at least I'm now able to make changes and apply them from a single command

Ansible can also be used for deployment, probably this going to be my next thing to learn, my starting point will be site deployment guide on the ansible documentation.

I'm closing this expecting the next time I will jump into learn more things about ansible I will try to create a proper task to create and add ssl certificate to the domains.

Another question I still have is how do I actually make the best workflow? Do I have one playbook for initial setup, another for specific upgrade?

By the way, still not response from Digital Ocean support. I had already moved my site to another droplet.

Below are some of the references I used. I mostly use everything on Digital Ocean ansible playbooks, and the Ansible documentation.

Reference:

Date:
Tags:
  • ansible
  • server