Table of Contents
- Prerequisites
- Workflow Overview
- Git and SSH Setup
- GitHub Repository Creation
- Ansible Galaxy Token Configuration
- GitHub Actions Automation
- Ansible Development Tools
- Role Testing with Molecule
- Publishing Process
- Troubleshooting
Prerequisites
Before starting, ensure you have the following:
- Operating System: Linux/macOS/WSL on Windows
- Python: Version 3.8 or higher
- Git: Latest version installed
- GitHub Account: For repository hosting
- Ansible Galaxy Account: For role publishing
- Docker: For testing with Molecule (optional but recommended)
Required Tools Installation
# Ubuntu/Debian
sudo apt update
sudo apt install git python3 python3-pip
# CentOS/RHEL/Fedora
sudo yum install git python3 python3-pip
# or
sudo dnf install git python3 python3-pipBashWorkflow Overview
graph TD
A[Start: Create Ansible Role] --> B[Git Repository Setup]
B --> C[SSH Key Configuration]
C --> D[GitHub Repository Creation]
D --> E[Local Repository Initialization]
E --> F[Ansible Galaxy Token Setup]
F --> G[GitHub Secrets Configuration]
G --> H[GitHub Actions Workflow]
H --> I[Development Tools Setup]
I --> J[Molecule Testing Setup]
J --> K[Role Development]
K --> L[Quality Checks]
L --> M{Tests Pass?}
M -->|No| K
M -->|Yes| N[Create Release Tag]
N --> O[GitHub Actions Triggers]
O --> P[Automatic Galaxy Publishing]
P --> Q[Role Available on Galaxy]
style A fill:#e1f5fe
style Q fill:#c8e6c9
style M fill:#fff3e0Git and SSH Setup
Step 1: Git Configuration
# Install Git (if not already installed)
sudo apt install git
# Create project directory
mkdir ansible-role-apache
cd ansible-role-apache/
# Configure Git globally (replace with your information)
git config --global user.name "Ankush More"
git config --global user.email "ankush.more.email@gmail.com"
git config --global init.defaultBranch main
git config --global core.autocrlf inputBashNote: The
core.autocrlfsetting helps handle line ending differences between operating systems.
Step 2: SSH Key Generation and Configuration
SSH keys provide secure authentication to GitHub without requiring passwords.
# Generate ED25519 SSH key (more secure than RSA)
ssh-keygen -t ed25519 -C "ankush.more.email@gmail.com"
# Start SSH agent
eval "$(ssh-agent -s)"
# Add SSH key to agent
ssh-add ~/.ssh/id_ed25519
# Display public key for copying to GitHub
cat ~/.ssh/id_ed25519.pubBashExpected Output:
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/terradmin/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/terradmin/.ssh/id_ed25519
Your public key has been saved in /home/terradmin/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:8xoNlczGRkvyqrNhriURgtH8k33O37653j0Rd1OEwdM ankush.more.email@gmail.com
The key's randomart image is:
+--[ED25519 256]--+
|.o . o ..=.|
| oo O o + E|
|. ...o @ ..|
| .+.. .= oo|
| .. +S =|
| . .o= . |
| . * ..o. .|
| = + o. .o o |
| ..o . o*o. o|
+----[SHA256]-----+
Agent pid 1153
Identity added: /home/terradmin/.ssh/id_ed25519 (ankush.more.email@gmail.com)
ssh-ed25519 AAAAC3Nza<...KEY...> ankush.more.email@gmail.com
Initialized empty Git repository in /home/terradmin/ansible-role-apache/.git/BashStep 3: Add SSH Key to GitHub
- Copy the SSH public key from the previous step
- Go to GitHub → Settings → SSH and GPG keys
- Click “New SSH key”
- Paste your public key and give it a descriptive title
- Click “Add SSH key”

Step 4: Test SSH Connection
# Test SSH connection to GitHub
ssh -T git@github.comBashYou should see a message like: “Hi username! You’ve successfully authenticated, but GitHub does not provide shell access.”
GitHub Repository Creation
Method 1: Create Repository on GitHub First (Recommended)
sequenceDiagram
participant User
participant GitHub
participant Local
User->>GitHub: Create new repository
Note over GitHub: Repository created with README
User->>Local: Clone repository
GitHub->>Local: Repository files downloaded
User->>Local: Add Ansible role files
User->>Local: Commit changes
User->>GitHub: Push changes- Create Repository on GitHub:
- Go to GitHub
- Click “New repository”
- Name:
ansible-role-apache(or your role name) - Description: Brief description of your role
- Choose Public (required for Galaxy)
- Initialize with README
- Add
.gitignore(Python template) - Choose a license (MIT, Apache 2.0, etc.)
- Clone Repository Locally:
# Clone the repository
git clone git@github.com:yourusername/ansible-role-apache.git
cd ansible-role-apacheBashMethod 2: Initialize Local Repository First
# Initialize local repository
git init
git add .
git commit -m "Initial commit"
# Create repository on GitHub first, then:
# Add remote origin
git remote add origin git@github.com:yourusername/ansible-role-apache.git
# Push to GitHub
git branch -M main
git push -u origin mainBashAnsible Galaxy Token Configuration
Step 1: Generate Galaxy API Token
- Login to Ansible Galaxy:
- Go to Ansible Galaxy
- Sign in with your GitHub account
- Generate API Token:
- Navigate to Token Management
- Click “Create Token”
- Provide a descriptive name (e.g., “GitHub Actions CI/CD”)
- Copy the generated token immediately (it won’t be shown again)

Step 2: Configure GitHub Repository Secrets
GitHub Secrets allow secure storage of sensitive information like API tokens.
graph TD
A[Galaxy Token Generated] --> B[GitHub Repository]
B --> C[Settings Tab]
C --> D[Secrets and Variables]
D --> E[Actions Tab]
E --> F[New Repository Secret]
F --> G[Add GALAXY_API_KEY]
G --> H[Token Stored Securely]
style A fill:#fff3e0
style H fill:#c8e6c9Steps to add the secret:
- Go to your GitHub repository
- Click Settings tab
- Navigate to Secrets and variables → Actions
- Click New repository secret
- Name:
GALAXY_API_KEY - Value: Paste your Galaxy API token
- Click Add secret

Step 3: GitHub Actions Token
GitHub automatically provides a GITHUB_TOKEN for Actions workflows with the following permissions:
- Read repository contents
- Write to repository (for releases)
- Read/write packages
For more information, see: Automatic token authentication

Ansible Development Tools
Installing Required Tools
# Configure pip to allow system packages (if needed)
python3 -m pip config set global.break-system-packages true
# Install Ansible and quality tools
pip install ansible ansible-lint molecule molecule-docker pytest-testinfra yamllint
# Add local bin to PATH (add to ~/.bashrc for persistence)
export PATH="~/.local/bin:$PATH"BashTool Descriptions
| Tool | Purpose | Configuration |
|---|---|---|
| ansible | Core Ansible automation engine | ansible.cfg |
| ansible-lint | Linting and best practices checker | .ansible-lint |
| molecule | Testing framework for Ansible roles | molecule/ directory |
| molecule-docker | Docker driver for Molecule | Included with molecule |
| pytest-testinfra | Infrastructure testing | molecule/default/tests/ |
| yamllint | YAML syntax and style checker | .yamllint |
Role Testing with Molecule
Initialize Molecule Testing
# Initialize molecule scenario with Docker driver
molecule init scenario -d dockerBashThis creates the following structure:
molecule/
└── default/
├── molecule.yml # Molecule configuration
├── converge.yml # Playbook to test
├── verify.yml # Additional verification tasks
└── tests/
└── test_default.py # Python tests with testinfraBashMolecule Configuration Example
Create molecule/default/molecule.yml:
---
dependency:
name: galaxy
driver:
name: docker
platforms:
- name: instance
image: quay.io/ansible/molecule-docker-runner-centos7
pre_build_image: true
provisioner:
name: ansible
verifier:
name: ansible
scenario:
test_sequence:
- dependency
- lint
- cleanup
- destroy
- syntax
- create
- prepare
- converge
- idempotence
- side_effect
- verify
- cleanup
- destroyYAMLRunning Tests
# Run full test suite
molecule test
# Run specific test phases
molecule lint # Lint the role
molecule converge # Run the role
molecule verify # Run verification tests
molecule destroy # Clean up test environmentBashGitHub Actions Automation
Creating the Workflow File
Create .github/workflows/release.yml:
---
name: Release to Galaxy
on:
push:
tags:
- 'v*' # Triggers on version tags like v1.0.0
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.9'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ansible ansible-lint yamllint
- name: Lint Ansible role
run: |
ansible-lint .
yamllint .
- name: Create Galaxy release
run: |
ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }} \
$(echo ${{ github.repository }} | cut -d/ -f1) \
$(echo ${{ github.repository }} | cut -d/ -f2)YAMLAdvanced Workflow with Testing
---
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
release:
types: [ published ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.8, 3.9, '3.10']
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install ansible ansible-lint molecule molecule-docker pytest-testinfra yamllint
- name: Lint with ansible-lint
run: ansible-lint .
- name: Test with molecule
run: molecule test
release:
needs: test
runs-on: ubuntu-latest
if: github.event_name == 'release'
steps:
- uses: actions/checkout@v4
- name: Release to Galaxy
run: |
ansible-galaxy role import --api-key ${{ secrets.GALAXY_API_KEY }} \
${{ github.repository_owner }} \
${{ github.event.repository.name }}YAMLPublishing Process
Step 1: Prepare Release
# Ensure all changes are committed
git add .
git commit -m "Prepare release v1.0.0"
# Create and push tag
git tag -a v1.0.0 -m "First release v1.0.0"
git push origin main --tagsBashRelease Process Flow
graph TD
A[Code Changes] --> B[Commit Changes]
B --> C[Create Git Tag]
C --> D[Push to GitHub]
D --> E[GitHub Actions Triggered]
E --> F[Run Tests]
F --> G{Tests Pass?}
G -->|No| H[Fix Issues]
H --> A
G -->|Yes| I[Lint Code]
I --> J{Lint Pass?}
J -->|No| H
J -->|Yes| K[Import to Galaxy]
K --> L[Role Published]
L --> M[Available on Galaxy]
style A fill:#e1f5fe
style M fill:#c8e6c9
style G fill:#fff3e0
style J fill:#fff3e0
Step 2: Verify Publication
- Check GitHub Actions workflow completion
- Visit Ansible Galaxy
- Search for your role:
namespace.role_name - Verify role information and documentation

Troubleshooting
Common Issues and Solutions
1. SSH Authentication Failed
# Problem: Permission denied (publickey)
# Solution: Check SSH key configuration
ssh-add -l # List loaded keys
ssh -T git@github.com # Test connectionBash2. Galaxy Import Failed
- Issue: Repository not public
- Solution: Make repository public in GitHub settings
- Issue: Invalid role structure
- Solution: Follow Ansible Galaxy role structure
3. GitHub Actions Workflow Failed
# Check workflow logs in GitHub Actions tab
# Common fixes:
env:
ANSIBLE_FORCE_COLOR: '1'
PY_COLORS: '1'YAML4. Molecule Test Failures
# Debug molecule issues
molecule --debug test
molecule login # Interactive debuggingBash5. Linting Errors
# Fix common ansible-lint issues
ansible-lint --fix .
# Check yamllint configuration
yamllint --config-file .yamllint .BashRole Structure Requirements
Your role must follow this structure for Galaxy compatibility:
ansible-role-name/
├── README.md
├── meta/
│ └── main.yml # Role metadata (required)
├── tasks/
│ └── main.yml # Main tasks
├── handlers/
│ └── main.yml # Handlers
├── templates/
├── files/
├── vars/
│ └── main.yml # Variables
├── defaults/
│ └── main.yml # Default variables
├── tests/
│ ├── inventory
│ └── test.yml
└── .github/
└── workflows/
└── release.yml # CI/CD workflowBashBest Practices
- Version Tagging: Use semantic versioning (v1.0.0, v1.1.0, v2.0.0)
- Documentation: Maintain comprehensive README.md
- Testing: Always test roles with Molecule before release
- Security: Never commit sensitive data; use variables and secrets
- Compatibility: Test across multiple OS distributions
- Idempotency: Ensure roles can run multiple times safely
Note: Replace yourusername and ansible-role-apache with your actual GitHub username and role name throughout this guide.
Discover more from Altgr Blog
Subscribe to get the latest posts sent to your email.
