This question already has an answer here:
Ansible shows error: "One or more undefined variables: 'item' is undefined" when using 'with_items'
(1 answer)
Closed 4 years ago.
ansible version
ansible --version
ansible 2.5.5
docker version
docker --version
Docker version 18.03.1-ce, build 9ee9f40
my Examples
- name: start container
docker_container:
name: "tomcat-container"
image: "tomcat-images"
state: started
ports:
- "{{ item[0]}}:{{ item[1] }}"
with_nested:
- [8080,8080]
- [8081,8081]
FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'item' is undefined\n\nThe error appears to have been in '/home/playbook/roles/ts-docker/tasks/main.yml': line 81, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: start container\n ^ here\n"}
...'item' is undefined
How to solve the problem of mounting multiple port?
-_-|| English is not good, forgive me
You just need to reduce the indent of the with_nested line like this:
- name: start container
docker_container:
name: "tomcat-container"
image: "tomcat-images"
state: started
ports:
- "{{ item[0]}}:{{ item[1] }}"
with_nested:
- [8080,8080]
- [8081,8081]
with_nested is an option for the task and the way you had it indented it was an option for the module (docker_container).
Related
I'm trying to make my first action to build packages inside a given docker container. I have the following action.yaml file:
name: Build Package
description: Build Debian packages using Docker image
inputs:
docker_image:
description: Name of the docker image to use
required: true
runs:
using: 'composite'
steps:
- name: Check out the repository
uses: actions/checkout#v2
- name: Build `*.deb` packages
uses: 'docker://${{inputs.docker_image}}'
with:
entrypoint: ./build.sh
In the other repository I'm trying to use it:
...
steps:
- uses: CMakeify-me/build-package-action#v1-beta
with:
docker_image: 'cmakeifyme/debian-9-deb-build:1.3'
Unfortunately, I've got the error:
Error: CMakeify-me/build-package-action/v1-beta/action.yaml (Line: 19, Col: 13):
Error: CMakeify-me/build-package-action/v1-beta/action.yaml (Line: 19, Col: 13): Unrecognized named-value: 'inputs'. Located at position 1 within expression: inputs.docker_image
Error: GitHub.DistributedTask.ObjectTemplating.TemplateValidationException: The template is not valid. CMakeify-me/build-package-action/v1-beta/action.yaml (Line: 19, Col: 13): Unrecognized named-value: 'inputs'. Located at position 1 within expression: inputs.docker_image
at GitHub.DistributedTask.ObjectTemplating.TemplateValidationErrors.Check()
at GitHub.Runner.Worker.ActionManifestManager.ConvertRuns(IExecutionContext executionContext, TemplateContext templateContext, TemplateToken inputsToken, String fileRelativePath, MappingToken outputs)
at GitHub.Runner.Worker.ActionManifestManager.Load(IExecutionContext executionContext, String manifestFile)
Error: Fail to load CMakeify-me/build-package-action/v1-beta/action.yaml
Trying just print the inputs works fine:
- name: Spam
run: echo '${{ inputs.docker_image }}'
shell: bash
Meaning, that there is some problem when inputs.docker_image is used within the value of uses: ;-(
How can I pass the docker image name to be used in my action?
Thank you.
I don't think you can't use an input/variable with uses like that.
This is not explicitly mentioned in the documentation but you can see a warning here: https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions
Warning: When creating workflows and actions, you should always consider whether your code might execute untrusted input from possible attackers.
If you need to dynamically pick your docker container, you might have to look into an alternative. You can avoid uses and run docker from shell directly, like this...
Call your action, and pass the input via with:
- uses: CMakeify-me/build-package-action#v1-beta
with:
docker_image: 'cmakeifyme/debian-9-deb-build:1.3'
Then your action can us the input via run, using shell to call docker:
- name: run docker with dynamic image name
run: 'docker run ${{ inputs.docker_image }}'
shell: bash
I'm trying to get Ansible to recreate an existing docker container in case one of the mounted files have changed. I tried to use docker_containerto remove the container, if it exists and any file has changed, before I deploy it using docker_stack and a compose file. Here is the code:
- name: Template configuration files to destination
template:
...
loop:
...
register: template_files_result
- name: Get docker container name
shell: "docker ps -f 'name=some_name' -q"
register: container_id
- name: Remove container
docker_container:
name: container_id.stdout
force_kill: yes
state: absent
vars:
files_changed: "{{ template_files_result | json_query('results[*].changed') }}"
when: container_id.stdout and files_changed is any
- name: Deploy
docker_stack:
state: present
name: stack_name
compose:
- "compose.yml"
with_registry_auth: true
However, the Remove container task never does anything and I can't figure out why.
What am I missing?
I'm using with_sequence to iteratively create copies of a container on a single node using ansible. The number of containers is determined by a variable set at the time of deploy. This works well for increasing the number of containers to scale up, but when I reduce the number to deploy less containers the old containers are left running. Is there a way to stop the old containers? Prune won't seem to work correctly since the old containers aren't stopped.
One option is to move from Ansible to docker-compose, which knows how to scale up and scale down (and honestly provides a better use experience for manage complex Docker configurations).
Another idea would be to include one loop for starting containers, and then a second loop that attempts to remove containers up to some maximum number, like this (assuming the number of containers you want to start is in the ansible variable container_count):
---
- hosts: localhost
gather_facts: false
vars:
container_count: 4
maximum_containers: 20
tasks:
- name: Start containers
docker_container:
state: present
name: "service-{{ item }}"
image: fedora
command: "sleep inf"
loop: "{{ range(container_count|int)|list }}"
- name: Stop containers
docker_container:
state: absent
name: "service-{{ item }}"
loop: "{{ range(container_count|int, maximum_containers|int)|list }}"
Called with the default values defined in the playbook, it would create 4 containers and then attempt to delete 16 more. This is going to be a little slow, since Ansible doesn't provide any way to prematurely exit a loop, but it will work.
A third option is to replace the "Stop containers" task with a shell script, which might be slightly faster but less "ansible-like":
---
- hosts: localhost
gather_facts: false
vars:
container_count: 4
tasks:
- name: Start containers
docker_container:
state: present
name: "service-{{ item }}"
image: fedora
command: "sleep inf"
loop: "{{ range(container_count|int)|list }}"
- name: Stop containers
shell: |
let i={{ container_count }}
while :; do
name="service-$i"
docker rm -f $name || break
echo "removed $name"
let i++
done
echo "all done."
Same idea, but somewhat faster and it doesn't require you to define a maximum container count.
Im working on a little Ansible project in which I'm using Docker Containers.
I'll keep my question short:
I want to get the state of a running Dockercontainer!
What I mean by that is, that i want to get the current state of the container, that Docker shows you by using the "docker ps" command.
Examples would be:
Up
Exited
Restarting
I want to get one of those results from a specific container. But without using the Command or the Shell module!
KR
As of Ansible 2.8 you can use the docker_container_info, which essentially returns the input from docker inspect <container>:
- name: Get infos on container
docker_container_info:
name: my_container
register: result
- name: Does container exist?
debug:
msg: "The container {{ 'exists' if result.exists else 'does not exist' }}"
- name: Print the status of the container
debug:
msg: "The container status is {{ result.container['State']['Status'] }}"
when: result.exists
With my Docker version, State contains this:
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 8235,
"ExitCode": 0,
"Error": "",
"StartedAt": "2019-01-25T14:10:08.3206714Z",
"FinishedAt": "0001-01-01T00:00:00Z"
}
See https://docs.ansible.com/ansible/2.8/modules/docker_container_info_module.html for more details.
Unfortunately, none of the modules around docker can currently "List containers".
I did the following as work around to grab the status:
- name: get container status
shell: docker ps -a -f name={{ container }} --format {%raw%}"table {{.Status}}"{%endraw%} | awk 'FNR == 2 {print}' | awk '{print $1}'
register: status
Result will then be available in the status variable
This worked for me:
- name: Get container status
shell: docker inspect --format={{ '{{.State.Running}}' }} {{ container_name }}
register: status
#Start the container if it is not running
- name: Start the container if it is in stopeed state.
shell: docker start heuristic_mestorf
when: status.stdout != "true"
Edit: If you are running Ansible 2.8+ you can use docker_container_info. See David Pärsson's answer for details.
Here is one way to craft it using the docker_container module (note that it will create the container if it does not exist):
- name: "Check if container is running"
docker_container:
name: "{{ container_name }}"
state: present
register: container_test_started
ignore_errors: yes
- set_fact:
container_exists: "{{ container_test_started.ansible_facts is defined }}"
- set_fact:
container_is_running: "{{ container_test_started.ansible_facts is defined and container_test_started.ansible_facts.docker_container.State.Status == 'running' }}"
container_is_paused: "{{ container_test_started.ansible_facts is defined and container_test_started.ansible_facts.docker_container.State.Status == 'paused' }}"
For me the gotchya was that if the container doesn't exist, ansible_facts is not defined. If it does though, then that contains basically the whole docker inspect <container> output so I navigate that for the status.
If you just need to short circuit, a simpler alternative would be to move the desired set_fact'd value into a failed_when on the docker_container task.
I do it through set_fact to keep my options open for forking behavior elsewhere.. e.g. stop, do task, then put back how it was.
I included pause because it is commonly forgotten as a state :)
There is an ansible module docker_image_facts which give you information about images. You are looking for something that would be docker_container_facts, which does not currently exist. Good idea though.
The question is not clear, but generally speaking you can use ansible with docker in two cases:
by using docker module of ansible
http://docs.ansible.com/ansible/latest/docker_module.html
- name: data container
docker:
name: mydata
image: busybox
state: present
volumes:
- /data
by calling ansible inside Dockerfile
FROM centos7
RUN ansible-playbook -i inventory playbook.yml
Your question is slightly unclear.
My best try - you want to have output of 'docker ps' - the first thing comes in mind is to use the Ansible command module, but you don't want to use it.
Then there are few docker modules:
docker - This is the original Ansible module for managing the Docker container life cycle.
docker_container - ansible module to manage the life cycle of docker containers.
You can look into the options -> parameters to get what exactly you're looking for.
Here's the complete list of Ansible modules for managing/using Docker.
I have a Concourse Pipeline with a Task using a Docker image that is stored in our local Artifactory server. Every time I start the Pipeline it takes about 5 mins until the tasks are finally run. The log looks like this:
I assume that Concourse somehow checks for newer versions of the Docker image. Unfortunately I have no chance to debug since all the logfiles on the Concourse worker VM offer no usable information.
My Questions:
How can I possibly debug what's going on, when Concourse says "preparing build" and the status is "pending".
Is there any chance to avoid Concourse from checking for a newer version of the Docker image? I tagged the Docker image with version latest - might this be an issue?
Any further ideas how I could speed things up?
Here is the detailed configuration of my pipeline and tasks:
pipeline.yml:
---
resources:
- name: concourse-image
type: docker-image
source:
repository: OUR_DOMAIN/subpath/concourse
username: ...
password: ...
insecure_registries:
- OUR_DOMAIN
# ...
jobs:
- name: deploy
public: true
plan:
- get: concourse-image
- task: create-manifest
image: concourse-image
file: concourse/tasks/create-manifest/task.yml
params:
# ...
task.yml:
---
platform: linux
inputs:
- name: git
- name: concourse
outputs:
- name: deployment-manifest
run:
path: concourse/tasks/create-and-upload-cloud-config/task.sh
The reason for this problem was that we pulled the Docker image from an internal Docker registry, which is running on HTTP only. Concourse tried to pull the image using HTTPS and it took around 5 mins until Concourse switched to HTTP (that's what a tcpdump on the worker showed us).
Changing the resource configuration to the following config solved the problems:
resources:
- name: concourse-image
type: docker-image
source:
repository: OUR_SERVER:80/subpath/concourse
username: docker-readonly
password: docker-readonly
insecure_registries:
- OUR_SERVER:80
So basically it was adding the port explicitly to the repository and the insecure_registries.