Installing Rancher with ansible - Lesson 3
Author: Stu FeeserIntroduction
In this lesson, we’re going to automate the installation of Rancher using Ansible. If you’ve been following along, you’ve likely installed Rancher manually and know that setting up authentication can be tedious.
That’s where Puppeteer comes in! Instead of manually configuring the Rancher UI, we’ll use a Node.js script with Puppeteer to handle password setup for us.
By the end of this post, you’ll have:
✅ A fully automated Rancher installation using Ansible
✅ Puppeteer automatically configuring your Rancher password
✅ A deeper understanding of how to structure a modular playbook
Make sure you have the puppeteer script from the second lesson.
📜 Click here to view the full puppeteer script
const fs = require('fs');
const puppeteer = require('puppeteer');
// ✅ Step 1: Get the new password from the command line
const newPassword = process.argv[2];
if (!newPassword) {
console.error("� Error: Please provide a new password as a command-line
argument.");
console.error("Usage: node rancher_setup.js 'YourNewPassword123'");
process.exit(1);
}
// ✅ Step 2: Read the hash password from the file
const passwordFilePath = '/home/student/pswd.txt';
if (!fs.existsSync(passwordFilePath)) {
console.error(`� Error: Password file not found at ${passwordFilePath}`);
console.error("Please create the file and add the hash password.");
console.error("Example: echo 'yourhashedpassword' > /home/student/pswd.txt");
process.exit(1);
}
const hashPassword = fs.readFileSync(passwordFilePath, 'utf8').trim();
// ✅ Step 3: Start Puppeteer Automation
(async () => {
const browser = await puppeteer.launch({
headless: true, // Set to false for debugging
ignoreHTTPSErrors: true,
args: [
'--ignore-certificate-errors',
'--no-sandbox',
'--disable-setuid-sandbox'
]
});
const page = await browser.newPage();
// -------------------------------
// Step 4: Open Rancher Setup Page
// -------------------------------
console.log("Opening initial Rancher setup page...");
await page.goto('https://controller-1', { waitUntil: 'networkidle2', timeout:
10000 });
// Wait for the password field (the one expecting the default hash)
await page.waitForSelector('#password', { visible: true, timeout: 10000 });
console.log("Filling in the hash password...");
await page.type('#password', hashPassword);
// Wait for and click the submit button
await page.waitForSelector('#submit', { visible: true, timeout: 10000 });
console.log("Submitting hash password...");
await page.click('#submit');
// -------------------------------
// Step 5: Change the Default Password
// -------------------------------
const radioSelector = 'span[aria-label="Set a specific password to use"]';
await page.waitForSelector(radioSelector, { visible: true, timeout: 10000 });
await page.click(radioSelector);
console.log(`Setting new password: ${'*'.repeat(newPassword.length)}`);
const newPasswordSelector = 'div[data-testid="setup-password"]
input[type="password"]';
await page.waitForSelector(newPasswordSelector, { visible: true, timeout:
10000 });
await page.type(newPasswordSelector, newPassword);
const confirmPasswordSelector = 'div[data-testid="setup-password-confirm"]
input[type="password"]';
await page.waitForSelector(confirmPasswordSelector, { visible: true, timeout:
10000 });
await page.type(confirmPasswordSelector, newPassword);
// -------------------------------
// Step 6: Accept EULA Agreement
// -------------------------------
console.log("Checking the EULA agreement...");
const eulaSelector = 'div[data-testid="setup-agreement"]
label[for="checkbox-eula"] span.checkbox-custom';
await page.waitForSelector(eulaSelector, { visible: true, timeout: 10000 });
await page.click(eulaSelector);
// -------------------------------
// Step 7: Submit the Form
// -------------------------------
console.log("Taking full-page screenshot before clicking the continue
button...");
await page.screenshot({ path: 'pre_submit.png', fullPage: true });
console.log("Clicking the continue button...");
await page.click('#submit button');
await new Promise(resolve => setTimeout(resolve, 5000));
console.log("Setup complete.");
await browser.close();
})();
Breaking Down the Ansible Playbook
Before diving into the full playbook, let’s break it down step by step. This will make it easier to understand the different tasks we need to accomplish.
Ensure that all necessary dependencies are installed, including:
✅ curl
and gnupg
(required for setting up Node.js)
✅ Node.js 18 from the NodeSource repository
✅ Puppeteer dependencies (various libraries)
✅ Docker (to run Rancher)
Step 1: Installing and Running Rancher on controller-1
The first playbook section installs and runs Rancher on the controller-1
node. Here we install docker, and run a daemonized Rancher container.
📌 Ansible Tasks:
- name: Install Rancher on controller-1
hosts: controller-1
become: true
tasks:
- name: Install Docker for Rancher to run in a container
apt:
name: docker.io
state: present
update_cache: yes
- name: Start and enable Docker service
systemd:
name: docker
state: started
enabled: yes
- name: Run Rancher container on controller-1 ### not idempotent
command:
cmd: >
docker run -d --restart=unless-stopped --name rancher
-p 80:80 -p 443:443 --privileged rancher/rancher:v2.6.9
args:
creates: /var/lib/docker/containers/rancher
register: rancher_run
changed_when: rancher_run.rc == 0
This ensures Rancher is installed inside a Docker container and ready to go.
Step 2: Retrieving and Copying the Rancher Bootstrap Password
Once Rancher starts, we give it a bit of time to finish initializing. We then extract the initial password hash from the logs and transfer it to the the bchd machine.
📌 Ansible Tasks:
- name: Wait for Rancher to initialize before moving on
pause:
seconds: 120
- name: Get Rancher Bootstrap Password
shell: |
docker logs rancher 2>&1 | grep "Bootstrap Password" | awk '{print $6}'
register: rancher_password
changed_when: false
- name: Save Bootstrap Password
copy:
content: "{{ rancher_password.stdout }}"
dest: /home/student/pswd.txt
owner: student
group: student
mode: '0600'
- name: Fetch Rancher current password from controller to localhost
fetch:
src: /home/student/pswd.txt
dest: /home/student/pswd.txt
flat: yes
This ensures the Rancher password is accessible on the bchd machine. It will be used shortly to verify access and allow us to set it to what we want.
Step 3: Setting Up Puppeteer on bchd
Now that we have the Rancher password, we can automate logging in and updating
the passwword using Puppeteer. This play runs against our localhost
, bchd.
First we install the required packages and libraries, then create our project
directories.
📌 Ansible Tasks:
- name: Setup Puppeteer on bchd
hosts: localhost
become: true
vars:
new_rancher_password: "passwordpassword"
puppeteer_project_path: "/home/student/puppeteer-project"
puppeteer_script: "update_rancher_passwd_w_puppeteer.js"
tasks:
- name: Install required system packages for node.js
apt:
name:
- curl
- gnupg
state: present
update_cache: yes
- name: Add NodeSource repository
shell: |
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
args:
executable: /bin/bash
- name: Install required libraries for Puppeteer
apt:
name:
- nodejs
- libatk1.0-0
- libatk-bridge2.0-0
- libcups2
- libxkbcommon-x11-0
- libgbm1
- libasound2
- libnss3
- libxcomposite1
- libxrandr2
- libxdamage1
- libpango-1.0-0
- libpangocairo-1.0-0
- libgdk-pixbuf2.0-0
- libegl1
- libgcrypt20
- libx11-xcb1
- libgtk-3-0
state: present
update_cache: yes
- name: Create Puppeteer project directory
file:
path: "{{ puppeteer_project_path }}"
state: directory
owner: student
group: student
mode: '0755'
Step 4: Running the Puppeteer Script
Finally, we execute the Puppeteer script to update the Rancher password. We go ahead and initialize the project, install Puppeteer, and run the puppeteer script we created in lesson two.
📌 Ansible Tasks:
- name: Initialize Node.js project
shell:
cmd: npm init -y
chdir: "{{ puppeteer_project_path }}"
creates: "{{ puppeteer_project_path }}/package.json"
- name: Install Puppeteer
shell:
cmd: npm install puppeteer
chdir: "{{ puppeteer_project_path }}"
creates: "{{ puppeteer_project_path }}/node_modules/puppeteer"
- name: Run Puppeteer script to update Rancher password
shell:
cmd: "node {{ puppeteer_project_path }}/{{ puppeteer_script }} '{{
new_rancher_password }}'"
args:
chdir: "{{ puppeteer_project_path }}"
register: puppeteer_result
- name: Debug Puppeteer script output
debug:
var: puppeteer_result.stdout
Full Ansible Playbook
For reference, here is the entire Ansible playbook, Put together piece by piece. Click below to expand to view the full file. This should be copiable if you are following along.
📜 Click here to view the full playbook
- name: Install Rancher on controller-1
hosts: controller-1
become: true
tasks:
- name: Install Docker for Rancher to run in a container
apt:
name: docker.io
state: present
update_cache: yes
- name: Start and enable Docker service
systemd:
name: docker
state: started
enabled: yes
- name: Run Rancher container on controller-1 not idemopotent
command:
cmd: >
docker run -d --restart=unless-stopped --name rancher
-p 80:80 -p 443:443 --privileged rancher/rancher:v2.6.9
args:
creates: /var/lib/docker/containers/rancher
register: rancher_run
changed_when: rancher_run.rc == 0
- name: Wait for Rancher to initialize before moving on
pause:
seconds: 120
- name: Get Rancher Bootstrap Password
shell: |
docker logs rancher 2>&1 | grep "Bootstrap Password" | awk '{print $6}'
register: rancher_password
changed_when: false
- name: Save Bootstrap Password
copy:
content: "{{ rancher_password.stdout }}"
dest: /home/student/pswd.txt
owner: student
group: student
mode: '0600'
- name: fetch Rancher current password from controller to localhost
fetch:
src: /home/student/pswd.txt
dest: /home/student/pswd.txt
flat: yes
- name: Setup Puppeteer on bchd
hosts: localhost
become: true
vars:
new_rancher_password: "passwordpassword" # Update this or pass via extra
vars
puppeteer_project_path: "/home/student/puppeteer-project"
puppeteer_script: "update_rancher_passwd_w_puppeteer.js"
tasks:
- name: Install required system packages for node.js
apt:
name:
- curl
- gnupg
state: present
update_cache: yes
- name: Add NodeSource repository
shell: |
curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
args:
executable: /bin/bash
- name: Install required libraries for Puppeteer
apt:
name:
- nodejs
- libatk1.0-0
- libatk-bridge2.0-0
- libcups2
- libxkbcommon-x11-0
- libgbm1
- libasound2
- libnss3
- libxcomposite1
- libxrandr2
- libxdamage1
- libpango-1.0-0
- libpangocairo-1.0-0
- libgdk-pixbuf2.0-0
- libegl1
- libgcrypt20
- libx11-xcb1
- libgtk-3-0
state: present
update_cache: yes
- name: Create Puppeteer project directory
file:
path: "{{ puppeteer_project_path }}"
state: directory
owner: student
group: student
mode: '0755'
- name: Initialize Node.js project
shell:
cmd: npm init -y
chdir: "{{ puppeteer_project_path }}"
creates: "{{ puppeteer_project_path }}/package.json"
- name: Install Puppeteer
shell:
cmd: npm install puppeteer
chdir: "{{ puppeteer_project_path }}"
creates: "{{ puppeteer_project_path }}/node_modules/puppeteer"
- name: Run Puppeteer script to update Rancher password
shell:
cmd: "node {{ puppeteer_project_path }}/{{ puppeteer_script }} '{{ new_rancher_password }}'"
args:
chdir: "{{ puppeteer_project_path }}"
register: puppeteer_result
- name: Debug Puppeteer script output
debug:
var: puppeteer_result.stdout
Create your inventory file
vim inventory.ini
[rancher]
controller-1 ansible_user=student ansible_become=true
Run the Playbook
ansible-playbook -i inventory.ini install_rancher.yml
Login to rancher with your new password
- User: admin
- Password: passwordpassword
Conclusion
This lesson took our manual Rancher setup and turned it into a fully automated deployment with Ansible and Puppeteer. Now, whenever you need to install Rancher, just run the playbook, sit back, and watch it configure itself! 🚀