{"id":51507950,"url":"https://github.com/explicit-logic/ansible-module-15.7","last_synced_at":"2026-07-08T02:30:43.238Z","repository":{"id":363921471,"uuid":"1264436264","full_name":"explicit-logic/ansible-module-15.7","owner":"explicit-logic","description":"Ansible Integration in Jenkins","archived":false,"fork":false,"pushed_at":"2026-06-10T22:53:55.000Z","size":4863,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-11T00:14:20.750Z","etag":null,"topics":["ansible","aws","boto3","devops-bootcamp","digitalocean","docker","jenkins","linux"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/explicit-logic.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-09T22:09:48.000Z","updated_at":"2026-06-10T23:05:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/explicit-logic/ansible-module-15.7","commit_stats":null,"previous_names":["explicit-logic/ansible-module-15.7"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/explicit-logic/ansible-module-15.7","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fansible-module-15.7","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fansible-module-15.7/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fansible-module-15.7/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fansible-module-15.7/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/explicit-logic","download_url":"https://codeload.github.com/explicit-logic/ansible-module-15.7/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/explicit-logic%2Fansible-module-15.7/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35249883,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-08T02:00:06.796Z","response_time":61,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","aws","boto3","devops-bootcamp","digitalocean","docker","jenkins","linux"],"created_at":"2026-07-08T02:30:42.350Z","updated_at":"2026-07-08T02:30:43.232Z","avatar_url":"https://github.com/explicit-logic.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Module 15 - Configuration Management with Ansible\n\nThis repository contains a demo project created as part of my **DevOps studies** in the [TechWorld with Nana – DevOps Bootcamp](https://www.techworld-with-nana.com/devops-bootcamp).\n\n**Demo Project:** Ansible Integration in Jenkins\n\n**Technologies used:** Ansible, Jenkins, DigitalOcean, AWS, Boto3, Docker, Java, Maven, Linux, Git\n\n**Project Description:**\n\n- Create and configure a dedicated server for Jenkins\n- Create and configure a dedicated server for Ansible Control Node\n- Write Ansible Playbook, which configures 2 EC2 Instances\n- Add ssh key file credentials in Jenkins for Ansible Control Node server and Ansible Managed Node servers\n- Configure Jenkins to execute the Ansible Playbook on remote Ansible Control Node server as part of the CI/CD pipeline\n- So the Jenkinsfile configuration will do the following:\n  - a.Connect to the remote Ansible Control Node server\n  - b.Copy Ansible playbook and configuration files to the remote Ansible Control Node server\n  - c.Copy the ssh keys for the Ansible Managed Node servers to the Ansible Control Node server\n  - d.Install Ansible, Python3 and Boto3 on the Ansible Control Node server\n  - e.With everything installed and copied to the remote Ansible Control Node server, execute the playbook remotely on that Control Node that will configure the 2 EC2 Managed Nodes\n\n---\n\n## Overview\n\n![](./images/overview.png)\n\nThe pipeline runs on **Jenkins**, copies the Ansible files to a remote **Ansible Control Node**, and from there runs a playbook that configures **2 EC2 Managed Nodes**. Ansible is agentless, so only the control node needs Ansible installed — the managed nodes are reached over plain SSH.\n\n### 1. Create and configure a dedicated server for Jenkins\n\nInstall Jenkins on DigitalOcean following the earlier modules:\n\n- https://github.com/explicit-logic/jenkins-module-8.1\n- https://github.com/explicit-logic/jenkins-module-8.2\n\n### 2. Create and configure a dedicated server for the Ansible Control Node\n\n- Create a droplet on DigitalOcean\n\n| Setting    | Value     |\n| ---------- | --------- |\n| CPU Option | Regular   |\n| vCPU       | 2         |\n| RAM        | 2 GB      |\n| Disk       | 60 GB     |\n\n![](./images/ansible-droplet.png)\n\nName it `ansible-server`.\n\nConnect to the droplet and install Ansible. `ansible-core` ships the `ansible-playbook` binary used later in the pipeline:\n\n```sh\nssh root@\u003cPUBLIC-IP\u003e\napt update\napt install ansible-core\n```\n\n\u003e 📚 [Ansible installation guide](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html)\n\nInstall the AWS SDK packages `boto3` / `botocore`. Ansible's `aws_ec2` **dynamic inventory** plugin uses them to query AWS for the managed nodes at runtime, so you never hardcode the EC2 IP addresses:\n\n```sh\napt install python3-boto3\n```\n\n\u003e 📚 [`amazon.aws.aws_ec2` inventory plugin](https://docs.ansible.com/ansible/latest/collections/amazon/aws/aws_ec2_inventory.html)\n\nConfigure AWS credentials so the plugin can authenticate against your account:\n\n```sh\nmkdir .aws\nvim .aws/credentials\n```\n\nCopy in your local default credentials (view them with `cat ~/.aws/credentials`):\n\n```conf\n[default]\naws_access_key_id = \u003cYOUR_ACCESS_KEY_ID\u003e\naws_secret_access_key = \u003cYOUR_SECRET_ACCESS_KEY\u003e\n```\n\n\u003e 📚 [AWS CLI — configuration and credential file settings](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html)\n\nExit the server.\n\n### 3. Create 2 EC2 instances to be managed by Ansible\n\nLaunch 2 Amazon Linux EC2 instances. Create a new key pair named `ansible-jenkins` and download the `.pem` file — Ansible will use it to SSH into the managed nodes as user `ec2-user`.\n\n![](./images/ec2-instances.png)\n\n### 4. Write the Ansible Playbook that configures the EC2 instances\n\nEverything the control node needs lives in the [`ansible/`](./ansible) directory.\n\n[`ansible.cfg`](./ansible/ansible.cfg) — points Ansible at the dynamic inventory and sets the SSH user and key used to reach the managed nodes:\n\n```conf\n[defaults]\nhost_key_checking = False\ninventory = inventory_aws_ec2.yaml\n\nenable_plugins = aws_ec2\n\nremote_user = ec2-user\nprivate_key_file = ~/ssh-key.pem\n```\n\n\u003e 📚 [Ansible configuration settings](https://docs.ansible.com/ansible/latest/reference_appendices/config.html)\n\n[`inventory_aws_ec2.yaml`](./ansible/inventory_aws_ec2.yaml) — the dynamic inventory. Set `regions` to the region your instances run in:\n\n```yaml\n---\nplugin: aws_ec2\nregions:\n  - eu-central-1\nkeyed_groups:\n  - key: tags\n    prefix: tag\n  - key: instance_type\n    prefix: instance_type\n```\n\n[`my-playbook.yaml`](./ansible/my-playbook.yaml) — installs Docker and the Docker Compose plugin on every managed node:\n\n```yaml\n---\n- name: Install Docker\n  hosts: all\n  become: yes\n  tasks:\n    - name: Install Docker\n      yum:\n        name: docker\n        update_cache: yes\n        state: present\n    - name: Start docker daemon\n      systemd:\n        name: docker\n        state: started\n\n- name: Install Docker-compose\n  hosts: all\n  tasks:\n    - name: Create docker-compose directory\n      file:\n        path: ~/.docker/cli-plugins\n        state: directory\n    - name: Get architecture of remote machine\n      shell: uname -m\n      register: remote_arch\n    - name: Install docker-compose\n      get_url:\n        url: \"https://github.com/docker/compose/releases/latest/download/docker-compose-linux-{{ remote_arch.stdout }}\"\n        dest: ~/.docker/cli-plugins/docker-compose\n        mode: +x\n```\n\n\u003e 📚 Modules used: [`ansible.builtin.yum`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/yum_module.html) · [`ansible.builtin.systemd_service`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/systemd_service_module.html) · [`ansible.builtin.file`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/file_module.html) · [`ansible.builtin.get_url`](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/get_url_module.html)\n\n### 5. Add SSH key credentials in Jenkins\n\nThe pipeline needs two SSH keys: one to reach the **control node** (DigitalOcean root key) and one to reach the **managed nodes** (the EC2 key pair).\n\n**a. Control Node key** — add a global credential in Jenkins\n\n- Kind: `SSH Username with private key`\n- ID: `ansible-server-key`\n- Username: `root`\n\nJenkins requires the classic **PEM** (`RSA`) key format. Convert the key you used to create `ansible-server` in place:\n\n```sh\nssh-keygen -p -f ~/.ssh/id_rsa -m pem -P \"\" -N \"\"\n```\n\nVerify the first line now reads `-----BEGIN RSA PRIVATE KEY-----`:\n\n```sh\ncat ~/.ssh/id_rsa\n```\n\nCopy the whole value into Jenkins.\n\n\u003e 📚 [Jenkins — using SSH credentials](https://www.jenkins.io/doc/book/using/using-credentials/) · [SSH Credentials plugin](https://plugins.jenkins.io/ssh-credentials/)\n\n**b. Managed Node key** — add a second global credential\n\n- Kind: `SSH Username with private key`\n- ID: `ec2-server-key`\n- Username: `ec2-user`\n\nCopy in the downloaded EC2 key:\n\n```sh\ncat ~/Downloads/ansible-jenkins.pem\n```\n\n![](./images/ec2-server-key.png)\n\n### 6. Jenkinsfile — copy files to the Ansible Control Node\n\nThis stage uses an `ANSIBLE_SERVER` build parameter (the public IP of the control node) and the two credentials above. It `scp`s the contents of `ansible/` to the control node and drops the EC2 key there as `ssh-key.pem` (the path `ansible.cfg` expects).\n\n```groovy\n      stage(\"copy files to ansible server\") {\n          steps {\n              script {\n                echo \"copying all neccessary files to ansible control node\"\n                withCredentials([sshUserPrivateKey(credentialsId: 'ansible-server-key', keyFileVariable: 'PK')]) {\n                  sh 'scp -o StrictHostKeyChecking=no -i $PK ansible/* root@$ANSIBLE_SERVER:/root'\n\n                  withCredentials([sshUserPrivateKey(credentialsId: 'ec2-server-key', keyFileVariable: 'keyFile')]) {\n                    sh 'scp -o StrictHostKeyChecking=no -i $PK $keyFile root@$ANSIBLE_SERVER:/root/ssh-key.pem'\n                  }\n                }\n              }\n          }\n      }\n```\n\n\u003e ⚠️ Note the **single quotes** around the `sh` steps. They let the shell — not Groovy — expand `$PK` / `$keyFile`, which keeps the secret out of the interpolated Groovy string (Jenkins warns about this otherwise).\n\u003e\n\u003e 📚 [`withCredentials` / `sshUserPrivateKey`](https://www.jenkins.io/doc/pipeline/steps/credentials-binding/) · [Handling credentials in a Jenkinsfile](https://www.jenkins.io/doc/book/pipeline/jenkinsfile/#handling-credentials)\n\n### 7. Create the Jenkins pipeline\n\n- Create a new item in Jenkins\n- Name: `ansible-pipeline`\n- Type: `Pipeline`\n\n![](./images/ansible-pipeline.png)\n\nConfigure **Pipeline script from SCM**:\n\n- Repository URL: https://github.com/explicit-logic/ansible-module-15.7\n- Credentials: `github` (username and password)\n- Branch Specifier: `main`\n\n![](./images/pipeline-scm.png)\n\nRun it with **Build with Parameters**, setting `ANSIBLE_SERVER` to the control node's public IP.\n\n![](./images/pipeline-copy-stage.png)\n\nConnect to the Ansible server and confirm the files transferred:\n\n```sh\nssh root@\u003cansible-server-ip\u003e\nls\n```\n\n![](./images/ansible-server-transfered-configs.png)\n\n### 8. Jenkinsfile — execute the Ansible Playbook on the Control Node\n\nInstall the Jenkins plugin **`SSH Pipeline Steps`** — it provides the `sshCommand` and `sshScript` steps.\n\n\u003e 📚 [SSH Pipeline Steps plugin](https://plugins.jenkins.io/ssh-steps/) · [step reference](https://www.jenkins.io/doc/pipeline/steps/ssh-steps/)\n\nAdd the stage below. Start with `ls -l` to confirm the SSH connection to the control node works:\n\n```groovy\n      stage(\"execute ansible playbook\") {\n        steps {\n          script {\n            echo \"calling ansible playbook to configure ec2 instances\"\n\n            def remote = [:]\n            remote.name = \"ansible-server\"\n            remote.host = \"$ANSIBLE_SERVER\"\n            remote.allowAnyHosts = true\n            withCredentials([sshUserPrivateKey(credentialsId: 'ansible-server-key', keyFileVariable: 'keyFile', usernameVariable: 'user')]) {\n              remote.user = user\n              remote.identityFile = keyFile\n              sshCommand remote: remote, command: \"ls -l\"\n            }\n          }\n        }\n      }\n```\n\n![](./images/exec-on-ansible-server.png)\n\nOnce the connection works, replace `ls -l` with the playbook run:\n\n```groovy\nsshCommand remote: remote, command: \"ansible-playbook my-playbook.yaml\"\n```\n\n![](./images/exec-playbook-from-jenkins.png)\n\n### 9. (Optional) Prepare the Control Node automatically\n\nInstead of installing Ansible/Boto3 on the control node by hand (step 2), let the pipeline do it. [`prepare-ansible-server.sh`](./prepare-ansible-server.sh) installs the prerequisites:\n\n```sh\n#!/usr/bin/env bash\n\napt update\napt install ansible -y\napt install python3-boto3\n```\n\nRun it from the pipeline with `sshScript`, just before the playbook command:\n\n```groovy\nsshScript remote: remote, script: \"prepare-ansible-server.sh\"\nsshCommand remote: remote, command: \"ansible-playbook my-playbook.yaml\"\n```\n\nExecute the pipeline.\n\n![](./images/demo.gif)\n\nVerify Docker landed on an EC2 managed node:\n\n```sh\nmv ~/Downloads/ansible-jenkins.pem ~/.ssh\nchmod 400 ~/.ssh/ansible-jenkins.pem\nssh -i ~/.ssh/ansible-jenkins.pem ec2-user@\u003cec2-ip-address\u003e\ndocker version\ndocker compose version\n```\n\n![](./images/check-ec2-docker.png)\n\n### Clean up\n\nTo avoid ongoing charges once the demo is done:\n\n- Terminate the 2 EC2 instances\n- Delete the `ansible-jenkins` EC2 key pair\n- Destroy the `ansible-server` DigitalOcean droplet (and the Jenkins droplet if no longer needed)\n- Remove the `ansible-server-key` and `ec2-server-key` credentials from Jenkins\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexplicit-logic%2Fansible-module-15.7","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fexplicit-logic%2Fansible-module-15.7","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fexplicit-logic%2Fansible-module-15.7/lists"}