sudo dnf install ansible-core -y
- Verify ansible command works to display the version
ansible --version
ansible [core 2.14.17]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/garfield/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.9/site-packages/ansible
ansible collection location = /home/garfield/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.9.19 (main, Sep 11 2024, 00:00:00) [GCC 11.5.0 20240719 (Red Hat 11.5.0-2)] (/usr/bin/python3)
jinja version = 3.1.2
==== Configure Ansible ====
- ansible.cfg file(s)
- Generate your own ansible.cfg in your home directory
ansible-config init --disabled -t all > ~/ansible.cfg
- Review the ansible.cfg file and make changes as desired
- setup Ansible static inventory
- Append the following to the bottom of the inventory file ( /etc/ansible/hosts )
[repo-servers]
repo.cloudclub.edu
[web-servers]
repo.cloudclub.edu
[dns-servers]
dns.cloudclub.edu
- Test inventory with command
ansible-inventory --graph
@all:
|--@ungrouped:
|--@repo_servers:
| |--repo.cloudclub.edu
|--@web_servers:
| |--repo.cloudclub.edu
|--@dns_servers:
| |--dns.cloudclub.edu
- Setup Ansible dynamic inventorya
- Setup ssh keys
- Generate ssh key pair - **Note**: Keep pressing enter ( 3 times ) for the default values until you get your command prompt back
ssh-keygen
- Copy the **public key** to the target devices - **Note**: type "yes" if prompted and enter the password when prompted
ssh-copy-id 192.168.1.11
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/garfield/.ssh/id_rsa.pub"
The authenticity of host '192.168.1.11 (192.168.1.11)' can't be established.
ED25519 key fingerprint is SHA256:CFrma1AskxuKYOHZm1mB0B4y1v1WPPhD2zD+TKcZHSY.
This host key is known by the following other names/addresses:
~/.ssh/known_hosts:1: repo.cloudclub.edu
Are you sure you want to continue connecting (yes/no/[fingerprint])? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
garfield@192.168.1.11's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh '192.168.1.11'"
and check to make sure that only the key(s) you wanted were added.
- Login to the target device and configure ssh with the following content to use the key by default
command
=============
sudo nano ~/.ssh/config
content
=============
Host *.cloudclub.edu
IdentityFile ~/.ssh/id_rsa
- Test the key by using ssh with the key
ssh 192.168.1.11
- Test inventory with command
ansible -m ping dns_servers
dns.cloudclub.edu | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
-----------------------------------------------------------------
ansible -m ping all
repo.cloudclub.edu | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
dns.cloudclub.edu | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
==== Ansbile Components ====
- Accessing and readding the Ansible documentation
- There are 2 ways to access the documentation
- Online
- You can use your browser to navigate through [[https://docs.ansible.com/]]
- **Easiest**: Google search for what you're tying to do
- Example search: "ansible add user" and select the top result ( reference: [[https://www.google.com/search?q=ansible+add+user]] )
- ansible-doc command
- To see a list of builtin modules
ansible-doc -l ansible.builtin
- To see the documentation on a particular module ( same one as above )
ansible-doc ansible.builtin.user
- Understand the components
- Modules
- Playbooks
- Tasks
- Roles
- collections
- List module collections with command
ansible-galaxy collection list
- Collection installation
ansible-galaxy collection install
- Offline collection installation
- Use a computer connected to the internet to find the collection on [[https://galaxy.ansible.com/ui/collections/]] and search for the collection you need. For example, you will find [[https://galaxy.ansible.com/ui/repo/published/ansible/windows/]] for the **ansible.windows** collection.
- Compare the installed ansible version from the command listed above with the version listed on the website. Lower the version number on the website until you are <= the installed version.
- Click the "Download tarball" link and save the tar.gz file(s) some place where you can transfer the file(s) to the ansible server.
- When you're in the directory containing the files, run the following installation command - **NOTE**: This command assumes you want to install the collection for the entire server instead of individual users.
sudo ansible-galaxy collection install * -p /usr/share/ansible/collections/
==== Writing Ansible code ====
- Prepare a location for your ansible codea
- Create a "code" directory
mkdir ~/code
cd ~/code
- As a best practice, create a local git repo
git init -b main ansible-basic
cd ansible-basic
- Create a playbook with tasks
- Edit a new file fist-playbook.yml and add the following content
- name: My first playbook
hosts: localhost
tasks:
- name: My first task
ansible.builtin.debug:
msg: Hello, user
- Run your shiny new playbook
ansible-playbook first-playbook.yml
PLAY [My first playbook] *************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************
ok: [localhost]
TASK [My first task] *****************************************************************************************************
ok: [localhost] => {
"msg": "Hello, user"
}
PLAY RECAP ***************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Use git command to add your file
git add first-playbook.yml
- Use git to create a "commit" object
git commit -m 'Initial version'
1 file changed, 9 insertions(+)
create mode 100644 first-playbook.yml
- Change the string "user" to a veriable
- name: My first playbook
hosts: localhost
vars:
user: Garfield
tasks:
- name: My first task
ansible.builtin.debug:
msg: Hello, {{ user }}
- Use the above git commands to add the file, create a new commit object with a different message
git add first-playbook.yml
git commit -m 'Add user variable'
1 file changed, 4 insertions(+), 1 deletion(-)
- ( Optional ) If you want to see the changes made to your files, use the git log command
git log
- Run your updated playbook
ansible-playbook first-playbook.yml
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [localhost]
TASK [My first task] ********************************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Hello, Garfield"
}
PLAY RECAP ******************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Createing roles
- Create ( initialize ) a new git repository
git init -b main ansible-roles
cd ansible-roles
mkdir roles
cd roles
- use the ansible-galaxy command to create the directory structure of a role
ansible-galaxy init docs
- Role docs was created successfully
- Install the **tree** command to help visualize the directory structure
sudo dnf install -y tree
- View the directory strcuture
tree
.
└── docs
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
9 directories, 8 files
- Add **"hidden"** files to instruct git to keep these empty directories
touch docs/files/.gitkeep
touch docs/templates/.gitkeep
- Run the tree command to show the differece
tree -a
.
└── docs
├── defaults
│ └── main.yml
├── files
│ └── .gitkeep
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
│ └── .gitkeep
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
9 directories, 10 files
- Change to the tasks directory
cd docs/tasks
- Edit the main.yml file with the following content
---
# tasks file for docs
- name: Create a directory
ansible.builtin.file:
path: /opt/docs
state: directory
user: nobody
group: nobody
mode: '0400'
- name: Create an empty file in the new directory
ansible.builtin.file:
path: /opt/docs/git-notes.txt
state: touch
- Add the new files and create a commit
git add -A
git commit -m 'Initial version - Add role'
10 files changed, 120 insertions(+)
create mode 100644 roles/docs/README.md
create mode 100644 roles/docs/defaults/main.yml
create mode 100644 roles/docs/files/.gitkeep
create mode 100644 roles/docs/handlers/main.yml
create mode 100644 roles/docs/meta/main.yml
create mode 100644 roles/docs/tasks/main.yml
create mode 100644 roles/docs/templates/.gitkeep
create mode 100644 roles/docs/tests/inventory
create mode 100644 roles/docs/tests/test.yml
create mode 100644 roles/docs/vars/main.yml
- Change to the "root" of the repo
cd ../..
- Create a playbook with the new role
nano doc-files.yml
- name: My first playbook
hosts: repo_servers
roles:
- name: docs
- Add and commit the new playbook
- Run the new playbook in **"check"** mode. This mode will run the code, but won't actually do the actions.
ansible-playbook doc-files.yml --check
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [repo.cloudclub.edu]
TASK [docs : Create a directory] ********************************************************************************************************************************************************************************
fatal: [repo.cloudclub.edu]: FAILED! => {"changed": false, "msg": "Unsupported parameters for (ansible.builtin.file) module: user. Supported parameters include: _diff_peek, _original_basename, access_time, access_time_format, attributes, follow, force, group, mode, modification_time, modification_time_format, owner, path, recurse, selevel, serole, setype, seuser, src, state, unsafe_writes (attr, dest, name)."}
PLAY RECAP ******************************************************************************************************************************************************************************************************
repo.cloudclub.edu : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- **Oops!** It looks like we found an error. Let's fix it.
- "msg": "Unsupported parameters for (ansible.builtin.file) module: user.
- Modify the docs/tasks/main.yml file to change 'user:' to 'owner:' and run the playbook again.
ansible-playbook doc-files.yml --check
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [repo.cloudclub.edu]
TASK [docs : Create a directory] ********************************************************************************************************************************************************************************
changed: [repo.cloudclub.edu]
TASK [docs : Create an empty file in the new directory] *********************************************************************************************************************************************************
changed: [repo.cloudclub.edu]
PLAY RECAP ******************************************************************************************************************************************************************************************************
repo.cloudclub.edu : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- It looks like we fixed it.
- Add and commit the changes
- Run the playbook again **without check mode**
ansible-playbook doc-files.yml
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [repo.cloudclub.edu]
TASK [docs : Create a directory] ********************************************************************************************************************************************************************************
fatal: [repo.cloudclub.edu]: FAILED! => {"changed": false, "msg": "There was an issue creating /opt/docs as requested: [Errno 13] Permission denied: b'/opt/docs'", "path": "/opt/docs"}
PLAY RECAP ******************************************************************************************************************************************************************************************************
repo.cloudclub.edu : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- **Oops!** Another error - See the task it failed on "TASK [docs | Create a directory ]" and the error itself -There was an issue creating /opt/docs as requested: [Errno 13] Permission denied: b'/opt/docs
- Update the main.yml file - add "become: true" to the bottom of the task like this. **Be sure to "outdent" the line**.
group: nobody
mode: '0400'
become: true
- Run the playbook again
- Yet another error. This time it's asking about the sudo password. Why? Because we added the "become: true" line. We told it to use sudo, but didn't give it a password to use.
- Run the playbook again, but add these 2 options
Options:
========
-k = ask ssh password
-K = ask sudo/become password
New command:
=============
ansible-playbook doc-files.yml -kK
ansible-playbook doc-files.yml -kK
SSH password:
BECOME password[defaults to SSH password]:
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [repo.cloudclub.edu]
TASK [docs : Create a directory] ********************************************************************************************************************************************************************************
changed: [repo.cloudclub.edu]
TASK [docs : Create an empty file in the new directory] *********************************************************************************************************************************************************
fatal: [repo.cloudclub.edu]: FAILED! => {"changed": false, "msg": "Error, could not touch target: [Errno 13] Permission denied: b'/opt/docs/git-notes.txt'", "path": "/opt/docs/git-notes.txt"}
PLAY RECAP ******************************************************************************************************************************************************************************************************
repo.cloudclub.edu : ok=2 changed=1 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
- We fixed the error for creating the directory, but we're failing to create the empty file. Why?
- Whom are we running the playbook as? YOU! -- More specifically, your user account that you loged into the ansible server with.
- What is the ownership and permissions of the directory? -- Owner: nobody -- Group: nobody -- Permissions: read-only for the owner and nothing for everyone elsae.
- Update the main.yml file to fix these things
- Run the playbook again - Success!!
ansible-playbook doc-files.yml -kK
SSH password:
BECOME password[defaults to SSH password]:
PLAY [My first playbook] ****************************************************************************************************************************************************************************************
TASK [Gathering Facts] ******************************************************************************************************************************************************************************************
ok: [repo.cloudclub.edu]
TASK [docs : Create a directory] ********************************************************************************************************************************************************************************
changed: [repo.cloudclub.edu]
TASK [docs : Create an empty file in the new directory] *********************************************************************************************************************************************************
changed: [repo.cloudclub.edu]
PLAY RECAP ******************************************************************************************************************************************************************************************************
repo.cloudclub.edu : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- What does the file ownership and permission look like now? -- System default, since we didn't specify them in our task to create the file.
- Create a collection with roles ??
==== Build a web server ====
- Create a role ( prefix with your initials ) to install and start nginx web server
- Update the role to configure and restart the webserver
- Create web content ( About me content ) as index.html
- Example playbook
- name: Setup web server
hosts: web_servers
roles:
- name: miked_web
- Example main.yml from the role
---
# tasks file for miked_web
- name: Install xnginx web server
ansible.builtin.dnf:
name: nginx
become: true
- name: Configure nginx web server to start
ansible.builtin.systemd_service:
name: nginx
enabled: true
state: started
become: true
- name: Add new file for web content
ansible.builtin.template:
src: templates/pg2.html.j2
dest: /usr/share/nginx/html/pg2.html
owner: garfield
group: garfield
mode: 774
become: true
- Example template:
Welcome, {{ ansible_user_gecos }}, from {{ ansible_host }}!!
Let's have some more fun. ;)
==== Backup your web content and rebuild ====
- Backup your web content with the tar command
- Create a new role to backup your site content by creating a .tar.gz or .tgz file.
- Destroy your VM
- Build a new server
- Restore your content from backup with the tar command ( or untar if you prefer )