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
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')
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?
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.
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?