How to run an ansible playbook using GitLab CI/CD?

Dhruvin Soni
Geek Culture
Published in
7 min readSep 6, 2021

--

What is GitLab CI/CD?

GitLab CI/CD is the part of GitLab that you use for all of the continuous methods (Continuous Integration, Delivery, and Deployment). With GitLab CI/CD, you can test, build, and publish your code with no third-party application or integration needed.

Read more about GitLab CI/CD here.

GitLab CI/CD

What is Ansible?

Ansible is an open-source software provisioning, configuration management, and deployment tool. It runs on many Unix-like systems and can configure both Unix-like systems as well as Microsoft Windows. Ansible uses SSH protocol in order to configure the remote servers. Ansible follows the push-based mechanism to configure the remote servers.

Ansible

What is Ansible Vault?

Ansible Vault is a feature of ansible that allows you to keep sensitive data such as passwords or keys in encrypted files, rather than as plaintext in playbooks or roles. You can create the new file as encrypted or can also modify the existing file as encrypted.

In this tutorial, I have integrated Ansible with GitLab CI/CD and created various resources on AWS.

GitLab CI/CD + Ansible

Prerequisite:

  • AWS & GitLab Account
  • Basic understanding of AWS, Ansible & GitLab CI/CD
  • An access key & secret key created in the AWS
  • Ansible Vault to encrypt the file

Lets, start with the configuration of the project

Step 1:- Create a Repository

  • Create a repository in your GitLab account & give it a name of your choice
GitLab Repository

Step 2:- Create an Ansible file for resource creation

  • Create a .yml file inside the root directory and add the below code in it.
  • The below code will create various resources on AWS. If you can’t understand anything in the code you can have a better understanding from here
---
- hosts: localhost # Place where we are running Ansible
connection: local # Connection
gather_facts: no
vars_files:
- cred.yml

# Variables
vars:
ansible_python_interpreter: /usr/bin/python3
# Default Names
title: "Demo"
vpc_name: "{{ title }} VPC"
igw_name: "{{ title }} IGW"
subnet_name: "{{ title }} Subnet"
acl_name: "{{ title }} ACL"
instance_name: "{{ title }} Instance"
security_group_name: "{{ title }} Security Group"
route_table_name: "{{ title }} Route Table"

# Default values for CIDR Blocks
vpcCidrBlock: "10.0.0.0/16"
subNetCidrBlock: "10.0.1.0/24"
portCidrBlock: "0.0.0.0/0"
destinationCidrBlock: "0.0.0.0/0"

# State
state: "present"

# Default value of AZ & Regio
zone: "us-west-1a"
region: "us-west-1"

# List of tasks
tasks:

# Creating VPC
- name: Create VPC
ec2_vpc_net:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
name: "{{ vpc_name }}"
cidr_block: "{{ vpcCidrBlock }}"
region: "{{ region }}"
dns_support: "yes"
dns_hostnames: "yes"
tenancy: "default"
state: "{{ state }}"
resource_tags:
Name: "{{ vpc_name }}"
register: vpc_result

# Creating Internate Gateway
- name: Create Internet Gateway
ec2_vpc_igw:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
vpc_id: "{{ vpc_result.vpc.id }}"
region: "{{ region }}"
state: "{{ state }}"
tags:
Name: "{{ igw_name }}"
register: igw_result

# Creating Subnet
- name: Create Subnet
ec2_vpc_subnet:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
vpc_id: "{{ vpc_result.vpc.id }}"
region: "{{ region }}"
state: "{{ state }}"
az: "{{ zone }}"
cidr: "{{ subNetCidrBlock }}"
map_public: "yes"
resource_tags:
Name: "{{ subnet_name }}"
register: subnet_result

# Creating Security Group
- name: Create Security Group
ec2_group:
name: "{{ security_group_name }}"
description: "{{ security_group_name }}"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
vpc_id: "{{ vpc_result.vpc.id }}"
region: "{{ region }}"
state: "{{ state }}"
tags:
Name: "{{ security_group_name }}"
rules:
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: "{{ portCidrBlock }}"
- proto: tcp
from_port: 443
to_port: 443
cidr_ip: "{{ portCidrBlock }}"
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: "{{ portCidrBlock }}"

rules_egress:
- proto: tcp
from_port: 80
to_port: 80
cidr_ip: "{{ portCidrBlock }}"
- proto: tcp
from_port: 443
to_port: 443
cidr_ip: "{{ portCidrBlock }}"
- proto: tcp
from_port: 22
to_port: 22
cidr_ip: "{{ portCidrBlock }}"
register: security_group_result

# Creating NACLs for subnet
- name: Create Network ACLs
ec2_vpc_nacl:
name: "{[ acl_name }}"
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
vpc_id: "{{ vpc_result.vpc.id }}"
region: "{{ region }}"
state: "{{ state }}"
subnets: [ "{{ subnet_result.subnet.id }}" ]
tags:
Name: "{{ acl_name }}"
ingress:
# rule no, protocol, allow/deny, cidr, icmp_type, icmp_code, port from, port to
- [100, 'tcp', 'allow', '0.0.0.0/0', null, null, 0, 65535]

# rule no, protocol, allow/deny, cidr, icmp_type, icmp_code, port from, port to
egress:
- [100, 'all', 'allow', '0.0.0.0/0', null, null, 0, 65535]

# Creating Route Table for subnet
- name: Create Route Table
ec2_vpc_route_table:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
vpc_id: "{{ vpc_result.vpc.id }}"
region: "{{ region }}"
state: "{{ state }}"
tags:
Name: "{{ route_table_name }}"
subnets: [ "{{ subnet_result.subnet.id }}" ]
routes:
- dest: "{{ destinationCidrBlock }}"
gateway_id: "{{ igw_result.gateway_id }}"
register: public_route_table

# Creating EC2 Instance
- name: Create EC2 Instance
ec2:
aws_access_key: "{{ aws_access_key }}"
aws_secret_key: "{{ aws_secret_key }}"
instance_type: t2.micro
image: ami-04b6c97b14c54de18
wait: yes
region: "{{ region }}"
group: "{{ security_group_name }}"
key_name: tests
count: 1
vpc_subnet_id: "{{ subnet_result.subnet.id }}"
assign_public_ip: yes
instance_tags:
Name: "{{ instance_name }}"
register: ec2_result

Step 3:- Create an ansible file for AWS Credentials

  • In this, I have used ansible vault to create the credentials file for the AWS access key & secret key so that we can manage it safely.

To create a new encrypted file using ansible vault you need to run the below command. It will ask for password so, please give a password that you can easily remember

ansible-vault create cred.yml
  • Add below content in it
aws_access_key: <your aws access key>
aws_secret_key: <your aws secret key>

Step 4:- Create a password file

  • Create a new file called password.txt and add your ansible vault password in it so that we can use it later.

Step 4:- Create a workflow file

  • Now in order to create the resources automatically, we need to create a workflow file
  • Create .gitlab-ci.yml file and add the below code to it
  • The below job will run on every push and pull request that happens on the master branch. In the build section, I have specified the image name and commands in the script section.
stages:
- run

image:
name: registry.gitlab.com/torese/docker-ansible

variables:
ANSIBLE_HOST_KEY_CHECKING: 'false'
ANSIBLE_FORCE_COLOR: 'true'
ANSIBLE_PYTHON_INTERPRRTER: /usr/bin/python3

before_script:
- yum install httpd -y
- yum install -y python3
- ansible --version

run:
stage: run
script:
- ansible-playbook main.yml --vault-password-file=password.txt

Let’s understand the above code.

  • The below code is to declare the name of the stage
stages:
- run
  • We are using ansible image to run the ansible playbook
image:
name: registry.gitlab.com/torese/docker-ansible
  • In the variable section we are defining environmental variables
variables:
ANSIBLE_HOST_KEY_CHECKING: 'false'
ANSIBLE_FORCE_COLOR: 'true'
ANSIBLE_PYTHON_INTERPRRTER: /usr/bin/python3
  • In the before_script section we are installing httpd and python3 and also checking the ansible version
before_script:
- yum install httpd -y
- yum install -y python3
- ansible --version
  • In the runsection we are running the ansible playbook
run:
stage: run
script:
- ansible-playbook main.yml --vault-password-file=password.txt

Step 5:- Check the output

  • Now, As soon as you commit your workflow file GitLab will trigger the action and the resources will be going to create on the AWS account.
  • After running the job you will see that all the steps run perfectly and there was no error. So you will have passedwritten in the green color as each step job successfully.
Jobs
  • You can also check the output of each step by clicking on it

Step 6:- Check the resources on AWS

  • As soon as the job finishes to run you can navigate to AWS and check all the resources
  • Ansible will create below resources
  1. VPC
VPC

2. Subnets

Subnets

3. Internet Gateway

Internet Gateway

4. Rouet Table

Route Table

5. Security Group

Security Group

6. Key Pair

Key Pair

7. EC2 Instance

EC2 Instance

That’s it now, you have learned how to integrate Ansible with GitLab CI/CD. You can now play with it and modify it accordingly.

If you found this guide helpful then do click on 👏 the button and also feel free to drop a comment.

Follow for more stories like this 😊

--

--

Dhruvin Soni
Geek Culture

Senior Cloud Infrastructure Engineer | AWS | Automation | 2x AWS | CKA | Terraform Certified | k8s | Docker | CI/CD | http://dhsoni.info/