0

I configured nginx on diffrent docker using ansible. Now I want to change different index.html using Jinja2.

I configured nginx using localhost. But now how can I use template Jinja2 and transfer it on container using ansible.

---
- hosts: localhost
  vars:
    server_name: "server"
  connection: local
  become: yes
  tasks:
  - package:
      name: docker
      state: present
  - service:
      name: docker
      state: restarted
  - command: docker run -it --name ngixserver21 -d -p 8090:80 nginx

#how I can transfer html_template.j2 on container - ngixserver21

  - name: Run a simple command (command)
    community.docker.docker_container_exec:
        container: ngixserver21
    template:
          src: "html_template.j2"
          desc: "/usr/share/nginx/html/index.html"
          notify: Restart Nginx
Zeitounator
  • 38,476
  • 7
  • 53
  • 66
Nav
  • 1
  • 1
  • 3
    The normal path I'd expect here is to rebuild the application image with the updated templates, then delete and recreate the container with the newer image. I would not try to automate `docker exec`; having locally modified code or assets in a container risks losing those changes when the container exits and doesn't work if the system can automatically scale or create containers (this is common in Kubernetes). – David Maze Feb 05 '22 at 12:01
  • 1
    To read further on what @DavidMaze stated, by having an image that you further customise after build time, you risk ending with a "golden image" (see https://stackoverflow.com/a/26111099/2123530) which is really not something you would like to end up with. – β.εηοιτ.βε Feb 05 '22 at 17:38

2 Answers2

0

I actually support what's been said in the comments. It's a little bit of anti-pattern.

I used something like this in the past. I'm sure you get the gist.

  - name: Run a simple command (command)
    community.docker.docker_container_exec:
        container: ngixserver21
        argv:
             - /bin/bash
             - "-c"
             - "echo {{ lookup('template', 'index.j2') | b64encode }} | base64 -d > index.html"
        chdir: "/usr/share/nginx/html"

    

This assumes of course that you have bash(sh should work too) and base64. If your template does not have single quotes, you may not need base64.

0

Important preliminary note: I urge you to read the comments from DavidMaze and β.εηοιτ.βε above regarding good practice to understand why you don't want to go through ansible in your specific case and you should not modify a running container.

Meanwhile, since there are other use cases (like testing ansible roles inside a docker container), I'll still answer the overall question hopping that all the above warnings were enough for you to use that information very wisely.

To start with, if you want to deploy and run your image with ansible, it should be done using the relevant docker_container module rather than calling shell.

Once this is done, ansible has a docker connection plugin that will let you interact with containers on your host 1. The idea is to have an entry in your inventory for the relevant container using the correctly configured connection. You can then use a normal play host loop with usual ansible tasks to reach your remote target container 2.

In my example below, I deploy an image and add it to the in-memory inventory in the same playbook using the add_host module. Those two actions can be done totally independently and there are several options to add your containers to an inventory among which the docker_containers dynamic inventory plugin.

I used the following test.j2 template for this test

Dummy template
Node name: {{ ansible_nodename }}
Environment:
{{ ansible_env | to_nice_yaml }}

This the demo playbook.yml:

---
- name: spin-up container and add to inventory
  hosts: localhost
  gather_facts: false

  vars:
    container_name: my_test_container

  tasks:
    - name: Deploy a dummy container
      docker_container:
        name: "{{ container_name }}"
        image: python:latest
        command: tail -f /dev/null
        state: started

    - name: store container name as a fact on localhost for later use in last play
      set_fact:
        container_name: "{{ container_name }}"

    - name: Add the created container to inventory
      add_host:
        name: "{{ container_name }}"
        groups:
          - docker_test
        ansible_connection: docker

- name: do some stuff on container
  hosts: docker_test

  tasks:
    - name: show a gathered info from the container
      debug:
        var: ansible_os_family

    - name: test our template is deployable
      template:
        src: test.j2
        dest: /test.txt

    - name: get result back to check
      slurp:
        path: /test.txt
      register: deploy_template

    - name: show result
      debug:
        msg: "{{ (deploy_template.content | b64decode).split('\n') }}"

    # Put here anything else that should target your container(s)

- name: do some cleanup
  hosts: localhost
  gather_facts: false

  tasks:
    - name: destroy test container
      docker_container:
        name: "{{ container_name }}"
        state: absent

Which gives:

$ ansible-playbook playbook.yml 

PLAY [spin-up container and add to inventory] *******************************

TASK [Deploy a dummy container] *********************************************
changed: [localhost]

TASK [store container name as a fact on localhost for later use in last play] *
ok: [localhost]

TASK [Add the created container to inventory] *******************************
changed: [localhost]

PLAY [do some stuff on container] *******************************************

TASK [Gathering Facts] ******************************************************
ok: [my_test_container]

TASK [show a gathered info from the container] ******************************
ok: [my_test_container] => {
    "ansible_os_family": "Debian"
}

TASK [test our template is deployable] **************************************
changed: [my_test_container]

TASK [get result back to check] *********************************************
ok: [my_test_container]

TASK [show result] **********************************************************
ok: [my_test_container] => {
    "msg": [
        "Dummy template",
        "Node name: 1608185a4e43",
        "Environment:",
        "GPG_KEY: A035C8C19219BA821ECEA86B64E628F8D684696D",
        "HOME: /root",
        "HOSTNAME: 1608185a4e43",
        "LANG: C.UTF-8",
        "PATH: /usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
        "PWD: /",
        "PYTHON_GET_PIP_SHA256: c518250e91a70d7b20cceb15272209a4ded2a0c263ae5776f129e0d9b5674309",
        "PYTHON_GET_PIP_URL: https://github.com/pypa/get-pip/raw/3cb8888cc2869620f57d5d2da64da38f516078c7/public/get-pip.py",
        "PYTHON_PIP_VERSION: 21.2.4",
        "PYTHON_SETUPTOOLS_VERSION: 57.5.0",
        "PYTHON_VERSION: 3.10.2",
        ""
    ]
}

PLAY [do some cleanup] ******************************************************

TASK [destroy test container] ***********************************************
changed: [localhost]

PLAY RECAP ******************************************************************
localhost:         ok=4    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
my_test_container: ok=5    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

1 docker plugin uses the docker cli to run commands. If you prefer to use the api directly, you can do the same thing with the docker-api plugin

2 Note that your target container will need to satisfy to ansible managed nodes requirements and have python installed


Zeitounator
  • 38,476
  • 7
  • 53
  • 66