Ansible Execution Environments

Introduction

Ansible as a automation platform offering is evolving further, making customer automation runtimes easier to setup and use. A feature coming to Ansible Automation Platform (AAP) soon will be something called execution environments.

EE's are designed to allow you to standard an 'automation runtime stack' which can run everywhere consistently, regardless of whether it's on a developers laptop, or in AAP, in cloud, wherever.

EE's essentially are an evolution to virtualenvs in Python/Ansible Tower.

venvs allow you to create sandbox environments containing all the necessary components, like module deps etc, which are required for the playbook/role runtime. These work a treat, but are a bit too much management for my liking!

So EE's are going to make this easier, better and consistent. Essentially, we're going to create a containerised image containing all our [venv] bits and associate that with the automation run.

This will be the underlying core engineering component of the next AAP release, and it'll be seamless to use.

For now though, let's play upstream and get something working so you can use it in operation.

Setup

My Environment:
Mac OSX Big Sur 11.2.1
Python 3.9.2
Docker Desktop 3.3.0 (62916)

First create a new python virtualenv where we'll install all the necessary software. This is the easiest way to get up and running without hitting issues in current environments.

mkdir ~/ansible-builder && cd ~/ansible-builder
python -m venv builder
source builder/bin/activate

(builder) pgriffit@pgriffit1-mac:~/ansible-builder:

Notice the (builder) in the command prompt now indicating we're using a venv.

Now we can install the software in this sandbox:

pip install ansible
pip install ansible-builder
pip install https://github.com/ansible/ansible-runner/archive/devel.zip

NB. I wanted to pull from the latest devel branch for ansible-builder, but it's not working at the moment.

You should now have a pip environment like this:

pip list

Package             Version
------------------- -------
ansible             3.2.0
ansible-base        2.10.8
ansible-builder     0.6.0
ansible-runner      2.0.0a1
cffi                1.14.5
cryptography        3.4.7
docutils            0.17
Jinja2              2.11.3
lockfile            0.12.2
MarkupSafe          1.1.1
packaging           20.9
pexpect             4.8.0
pip                 21.0.1
ptyprocess          0.7.0
pycparser           2.20
pyparsing           2.4.7
python-daemon       2.3.0
PyYAML              5.4.1
requirements-parser 0.2.0
setuptools          54.1.2
six                 1.15.0


Now make sure that docker is running as ansible-builder and runner will be using it to create and spin up container runtimes.

Creating an EE (container image)

tree -L 1
.
├── builder
├── context
├── execution-environment.yml
├── requirements.txt
├── requirements.yml
├── strategy.yml
└── test.yml


2 directories, 5 files

We're going to end up with something like the above.

For now we can ignore builder/ and context/ as this is where things get installed and created for us.

We're going to need to create a few config files and a playbook or two, for the automation run.

cat execution-environment.yml

---
version: 1
dependencies:
  galaxy: requirements.yml
  python: requirements.txt


additional_build_steps:
  prepend: |
    RUN pip3 install --upgrade pip setuptools
  append:
    - RUN ls -la /etc

This is the main EE config file, which pulls in others that we want to include in the image build.

The only things I've created here are:

cat requirements.yml

---
collections:
  - community.general

This is what collections I want to include in my build (cos they're required in my playbook).

cat requirements.txt

urllib3

This is what python [pip] modules I want to include within the EE.

Let's Build!

ansible-builder build --tag my_first_ee_image --container-runtime docker
Running command:
  docker build -f context/Dockerfile -t my_first_ee_image context
Running command:
  docker run --rm -v /Users/pgriffit/ansible-builder/builder/lib/python3.9/site-packages/ansible_builder:/ansible_builder_mount:Z my_first_ee_image python3 /ansible_builder_mount/introspect.py
Running command:
  docker build -f context/Dockerfile -t my_first_ee_image context
Complete! The build context can be found at: /Users/pgriffit/ansible-builder/context

After a little while, you should be able to see the docker registry image:

docker images | grep my_first_ee_image
my_first_ee_image                latest    872f5dc0bd67   8 seconds ago       615MB

Let's Run It!

Ok, so we should now be able to use ansible-runner to fire things off and check our EE.

I created a noddy little playbook for a check. Remember we added urllib3 as a python module dependency? Well my local venv doesn't have this but the EE should.

cat test.yml

---
- hosts: localhost
  connection: local
  gather_facts: false


  tasks:
  - name: Just get the list from default pip
    community.general.pip_package_info:
      clients: pip
    register: pips

  - debug:
      msg: "{{ pips.packages.pip.urllib3 | default('nope, not installed') }}"

Let's run some local checks:

ansible-playbook test.yml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'


PLAY [localhost] ***************************************************************************************************************************************


TASK [Just get the list from default pip] **************************************************************************************************************
ok: [localhost]


TASK [debug] *******************************************************************************************************************************************
ok: [localhost] => {
    "msg": "nope, not installed"
}


PLAY RECAP *********************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

So using our normal ansible-playbook command we can use that there is no urllib8 module installed, which is correct.

Likewise, we can use ansible-runner to do a local check as well:

ansible-runner run -p test.yml .
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'


PLAY [localhost] ***************************************************************


TASK [Just get the list from default pip] **************************************
ok: [localhost]


TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": "nope, not installed"
}


PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Now, let's check our new EE!

ansible-runner playbook --container-runtime docker --container-image my_first_ee_image test.yml
[WARNING]: You are running the development version of Ansible. You should only
run Ansible from "devel" if you are modifying the Ansible engine, or trying out
features under development. This is a rapidly changing source of code and can
become unstable at any point.
[WARNING]: You are running the development version of Ansible. You should only
run Ansible from "devel" if you are modifying the Ansible engine, or trying out
features under development. This is a rapidly changing source of code and can
become unstable at any point.
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that
the implicit localhost does not match 'all'


PLAY [localhost] ***************************************************************


TASK [Just get the list from default pip] **************************************
ok: [localhost]


TASK [debug] *******************************************************************
ok: [localhost] => {
    "msg": [
        {
            "name": "urllib3",
            "source": "pip",
            "version": "1.26.4"
        }
    ]
}


PLAY RECAP *********************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0


As you can see that EE has been built with my requirements to create the all-in-one environment I need for this automation.

You can create as few or as many EE's as you need to support, and use them against your automation runs. If you're maintaining or pinning a lot of venvs to cope with supporting multiple versions and platforms etc, then this should be right up your street!

These EE's are the future of Ansible platform automation. More to come on this for sure!

Pssst! Just for fun, try running another playbook with the same EE just to show that's a thing, err something like...

cat strategy.yml

---
- hosts: localhost
  connection: local
  gather_facts: false


  tasks:
  - name: "Quick! Panic! We need a new corporate strategy"
    ansible.builtin.uri:
      url: https://strategy-madlibs.herokuapp.com/
      return_content: true
      body_format: json
    register: strategy


  - debug:
      msg: "{{ strategy.content | regex_search('<title>(.*)</title>', '\\1') }} + {{ strategy.content | regex_search('(Our strategy is .*).', '\\1') }}"

(source is available here: https://github.com/ffirg/strategy)

ansible-runner playbook --container-runtime docker --container-image my_first_ee_image strategy.yml


Krishna Gopal Singh

BMC Discovery | Device42 | Azure Migrate | Cloud Migrations (Rehost, Replatform) | Ansible | Terraform | AWS | Azure | IBM Cloud | Remedy ITSM | CMDB

3 年

Hello Phil, I am getting usage error while running ansible-runner playbook --container-runtime docker --container-image my_first_ee_image test.yml ansible-runner: error: argument command: invalid choice: 'playbook' (choose from 'run', 'start', 'stop', 'is-alive', 'transmit', 'worker', 'process')

回复
Jeroen Kleijer

Technical Specialist at Sue B.V

3 年

Hi Phil, Is it possible to pass options along to podman to tell it not to relabel files? I'm trying to run a custom container-image (as non-root) from a NFS mount point and it doesn't seem to like this very much: "Error: relabeld failed "/.....": failed to set file label on ....: operation not supported. Is this a specific parameter I'd need to pass along with --container-option or a config file?

回复
Brendan Wood

Sr. Linux Engineer at Mercy

3 年

any idea when the playbook option is targeted to be merged into the main branch? 2.0.2 does not appear to have this option, although appears later than the version in your example.

回复
Dave Jia

SW System Senior Engineer at Dell EMC

3 年

Hi Phil, it seems like --extra-index-url is not supported in requirements.txt while buiding up the custom EE, any plan to support it?

回复

要查看或添加评论,请登录

Phil Griffiths的更多文章

  • Still using vi for Ansible? No problem!

    Still using vi for Ansible? No problem!

    Having grown up using vi as a main editor on UN*X systems, I still love it and often fire it up for quick demos etc. I…

    3 条评论
  • Calling the Ansible Automation Platform API Using 'Friendly' Job Template Names

    Calling the Ansible Automation Platform API Using 'Friendly' Job Template Names

    Have you ever wanted to call the AAP/Tower API to launch a Job Template? The REST API allows you to do that, fast and…

    1 条评论
  • Creating a custom EE for AWX

    Creating a custom EE for AWX

    This is a quick and rough guide to creating and consuming a custom execution environment (EE) in AWX. What You'll Need…

    29 条评论
  • AWX 18.0.0 with Containerised Execution Environments

    AWX 18.0.0 with Containerised Execution Environments

    The upstream of Ansible Automation Platform, AWX has just landed with a new exciting release. Thought I'd give it a try…

    4 条评论
  • Ansible Features I Missed

    Ansible Features I Missed

    Well, ok some of these aren't particularly new, but I've only just become aware of them. Even after years of Ansible…

    4 条评论
  • Tuning RHEL Using Ansible System Roles

    Tuning RHEL Using Ansible System Roles

    Take the pain out of some performance tuning using RHEL's tuned functionality. Take even more pain out setting it up…

    1 条评论
  • Oh Molecule You've Come A Long Way

    Oh Molecule You've Come A Long Way

    I often get asked about Ansible testing, best practices and related topics. If there's one tool I'd have in the kit bag…

    4 条评论
  • Holy crap batman! sudo's bust!

    Holy crap batman! sudo's bust!

    As we all know, software has bugs, no one escapes! How you respond and fix those bugs is what's important. If you ever…

    1 条评论
  • RHEL OS Image Builder (part two)

    RHEL OS Image Builder (part two)

    This is part 2 of the blog series. Part one is here.

    1 条评论
  • RHEL8 OS Image Builder (part one)

    RHEL8 OS Image Builder (part one)

    Following on from this post for setting up a quick RHEL VM with minimal fuss, this is what I really wanted it for!…

社区洞察

其他会员也浏览了