Ansible Provisioning

Created:
Last Update:

Author: Christoph Stoettner
Read in about 5 min · 975 words

Fountain pen and a notebook

Photo by Aaron Burden | Unsplash

In the first two parts of this little devops series, I showed build templates with Packer and deploying virtual-machines with Terraform .

Now we want to install some more packages on our new servers.

tl;dr

I started using Ansible for deployments some years ago. For example I showed deploying IBM Connections at Social Connections 12 in Vienna .

For more details on the functionality, have a look at the post How Ansible Works

Ansible uses plain ssh and doesn’t need any additional server or client component.

You can run Ansible as a separate task in your deployment pipeline, or add it as post-provisioning task to Terraform. So it runs automatically when Terraform deploys your systems.

Windows

You can use Ansible to deploy Windows Servers too. More interesting is running Ansible from a Windows machine to deploy Linux and Windows servers.

For Windows you can use WinRM or SSH to connect for remote management. The SSH support is experimental AFAIK.

Ansible

Installation

Ansible is available for all major Linux distributions. Check the documentation for installation instructions .

Little project

Directory structure of a little Ansible example

.
├── group_vars
│   └── all
│       └── main.yml
├── inventory
├── roles
│   ├── common
│   │   └── tasks
│   │       └── main.yml
│   └── ldap
│       ├── defaults
│       │   └── main.yml
│       └── tasks
│           └── main.yml
├── site.yml
└── templates
    ├── base.ldif.j2
    ├── db.ldif.j2
    ├── ldap-config.sh.j2
    ├── monitor.ldif.j2
    └── user-ldap.ldif.j2

In the inventory file you define your servers and group them together.

inventory

[gpn19]
gpn19-server1
gpn19-server2

[ldap]
gpn19-server2

So gpn19-server1 is only in the group gpn19, server gnp19-server2 is part of gpn19 and ldap. There is always a group all with all servers of an inventory file.

The Ansible playbook itself is defined as an Yaml-file:

site.yml

---
- hosts: all
  roles:
    - common

- hosts: ldap
  roles:
    - role: ldap

So for all hosts the role common will run and on group ldap the role ldap.

To make the roles independent of the environment, we use some variables. So it’s enough to just change the variable and the deployment will use different domain and passwords.

group_vars/all/task.yml

---
ldap:
  domain: dc=devops,dc=example,dc=com
  passwordencrypted: "{SSHA}CdGAzVNlrqgLbKo6pebBxuDBBkxokkHm"
  passwordclear: "password"

To keep it simple, the password is defined here in the variable file. Have a look at Ansible Vault to keep your passwords encrypted.

Using template files

For the ldap deployment we need to change some files on the target server. These are already prepared in the directory templates and use Jinga2 template engine .

templates/ldapconfig.sh.j2

#!/usr/bin/env bash

cd /etc/openldap/slapd.d
ldapmodify -Y EXTERNAL  -H ldapi:/// -f db.ldif
ldapmodify -Y EXTERNAL  -H ldapi:/// -f monitor.ldif
sleep 5
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
sleep 5
ldapadd -x -w {{ ldap.passwordclear }} -D "cn=ldapadm,{{ ldap.domain }}" -f /etc/openldap/slapd.d/base.ldif   
sleep 10
ldapadd -x -w {{ ldap.passwordclear }} -D "cn=ldapadm,{{ ldap.domain }}" -f /etc/openldap/slapd.d/user-ldap.ldif
  • We can use our variable in Jinga2 and these will be replaced during deployment

roles/common/tasks/main.yml

---
# Disable Firewall during Installation
- name: Disable Firewall  
  service:
    name=firewalld
    state=stopped
    enabled=no

# Disabe SELinux, most IBM Software is not supported with it
- name: Disable SELinux
  selinux:
    state: disabled

# Increase limits.conf for IBM products
- name: Change limits.conf    
  pam_limits:
    domain: root
    limit_type: '-'
    limit_item: nproc
    value: '16384'
- pam_limits:
    domain: root
    limit_type: '-'
    limit_item: nofile
    value: '65536'
- pam_limits:
    domain: root
    limit_type: '-'
    limit_item: stack
    value: '10240'

# Install Unzip
- name: Install unzip to support unarchive function of ansible, add xauth
  package:
    name={{ item }}       
    state=latest
  with_items:
    - unzip
    - xauth
    - vim

# Configure SSH X11Forward
- name: Update SSH configuration to be more secure.
  lineinfile:
    dest: "/etc/ssh/sshd_config"
    regexp: "{{ item.regexp }}"
    line: "{{ item.line }}"
    state: present
  with_items:
    - regexp: "^X11Forwarding"
      line: "X11Forwarding yes"
    - regexp: "^X11UseLocalhost"
      line: "X11UseLocalhost no"
- name: Restart SSH
  service:
    name=sshd
    state=restarted
    enabled=yes
  • Stop Firewalld and set to disabled

  • Configure some limits in limits.conf

  • Install additional packages (independent of yum or apt)

roles/ldap/tasks/main.yml

---
- name: Install system packages for OpenLDAP
  package:
    name={{ item }}
    state=latest
  with_items:
    - openldap-servers
    - openldap-clients

- name: Enable Slapd service    
  service:
    name=slapd
    state=restarted
    enabled=yes

- name: Initial ldap config, copy templates db.ldif   
  template: src=db.ldif.j2 dest=/etc/openldap/slapd.d/db.ldif
  tags: parse

- name: Initial ldap config, copy templates monitor.ldif
  template: src=monitor.ldif.j2 dest=/etc/openldap/slapd.d/monitor.ldif
  tags: parse

- name: Create base.ldif
  template: src=base.ldif.j2 dest=/etc/openldap/slapd.d/base.ldif
  tags: parse

- name: Create user.ldif
  template: src=user-ldap.ldif.j2 dest=/etc/openldap/slapd.d/user-ldap.ldif
  tags: parse

- name: Copy sample db config
  copy:
    src: "/usr/share/openldap-servers/DB_CONFIG.example"
    dest: "/var/lib/ldap/DB_CONFIG"
    remote_src: yes
    directory_mode: yes
    owner: ldap
    group: ldap

- name: Create LDAP Config Script
  template:
    src: ldap-config.sh.j2
    dest: /tmp/ldap-config.sh
    mode: 0755
  tags: parse

- name: Configure LDAP and Import Users
  shell: "/tmp/ldap-config.sh"

- name: Remove config script
  file:
    path: /tmp/ldap-config.sh
    state: absent
  • Enable slapd service

  • Copy db.ldif.j2 from templates to dest

Run Ansible Playbook

To run this playbook with our inventory file, just run:

ansible-playbook -i inventory site.yml

So now you’re prepared to build new servers and deploy software on it. Have fun!

Ansible Galaxy

On Ansible Galaxy you can share and download Ansible roles. So start new projects searching there, don’t start from scratch.

Galaxy is a hub for finding and sharing Ansible content.

Use Galaxy to jump-start your automation project with great content from the Ansible community. Galaxy provides pre-packaged units of work known to Ansible as Roles, and new in Galaxy 3.2, Collections.

Roles can be dropped into Ansible PlayBooks and immediately put to work. You’ll find roles for provisioning infrastructure, deploying applications, and all of the tasks you do everyday. The new Collection format provides a comprehensive package of automation that may include multiple playbooks, roles, modules, and plugins.

Gulasch Programmiernacht

The content of this series was part of my talk at the GPN19. So you can watch a video of the talk too:

<iframe width=“1024” height=“576” src=“https://media.ccc.de/v/gpn19-111-automate-your-virtual-server-deployments/oembed" frameborder=“0” allowfullscreen></iframe>

Author
Add a comment
Error
There was an error sending your comment, please try again.
Thank you!
Your comment has been submitted and will be published once it has been approved.

Your email address will not be published. Required fields are marked with *

Suggested Reading
Aaron Burden: Fountain pen and a notebook

My last article showed how to build a server template with Packer .

Now we want to use this template to create some servers on VMware vSphere. DNS will be registered manually and all IP addresses will be defined as fixed in the config files.

Created:
Last Update:
Read in about 6 min
Card image cap

In the post Create A Test Environment with Terraform and KVM I created the first three virtual machines, now we configure a DNS server so name resolution works as expected.

Since HCL Connections started to add Kubernetes to the stack, we need to use proper name resolution instead of just editing /etc/hosts. That’s a bit of an effort, but in the end it is way easier than checking several hosts if the hosts file is uptodate.

Created:
Last Update:
Read in about 7 min
Aaron Burden: Fountain pen and a notebook

For GPN19 I prepared a second talk on Documentation with any Editor . The talk was based on a previous one from Froscon 13, but the pipeline tooling changed.

This time there was a technical issue during the recording and so there are only the slides available, but you can still watch the video of the Froscon talk: Froscon 13: Documentation with any Editor

Created:
Last Update:
Read in about 8 min