【问题标题】:Ansible: How to set docker container labels with dynamic key names?Ansible:如何使用动态键名设置 docker 容器标签?
【发布时间】:2020-09-12 13:53:24
【问题描述】:

我尝试使用 traefik 标签启动 docker 容器。 要为容器创建 traefik 路由器,您必须像这样放置一些标签。

app_names:
  - tower01
  - tower02

docker_labels:
    awx_web:
      traefik.enable: "true"
      traefik.http.routers.{{ app_name }}.entrypoints: "http"
      traefik.http.routers.{{ app_name }}.rule: "Host(`{{ app_server_fqdn }}`)"
      traefik.http.routers.{{ app_name }}.middlewares: "https-redirect@file"
      traefik.http.routers.{{ app_name }}-sec.entrypoints: "https"
      traefik.http.routers.{{ app_name }}-sec.rule: "Host(`{{ app_server_fqdn }}`)"
      traefik.http.routers.{{ app_name }}-sec.tls: "true"
      traefik.http.routers.{{ app_name }}-sec.tls.options: "myTLSOptions@file"
      traefik.http.routers.{{ app_name }}-sec.tls.certresolver: "le"
      traefik.http.routers.{{ app_name }}-sec.middlewares: "default-headers@file"
      traefik.http.services.{{ app_name }}.loadbalancer.server.port: "8052"
      com.centurylinklabs.watchtower.enable: "{{ autoupdate_container[loop_item] }}"

并使用与此类似的任务:

- name: "{{ app_name }} | create awx web container"
  docker_container:
    name:           "{{ app_name }}-web"
    hostname:       "awxweb"
    user:           "root"
    image:          "ansible/awx_web:{{ docker_image[loop_item] | default('latest') }}"
    env:            "{{ docker_env[loop_item] | default(omit) }}"
    networks:       [ name: "{{ app_name }}" ]
    purge_networks: true
    volumes:        "{{ docker_volumes[loop_item] | default(omit) }}"
    restart_policy: "unless-stopped"
    labels:         "{{ docker_labels[loop_item] | default(omit) }}"
    state:          "{{ state | default('started') }}"
  loop: "{{ app_names }}"

标签当然应该是:

traefik.http.routers.tower01.entrypoints: "http"
traefik.http.routers.tower01.rule: "Host(`{{ app_server_fqdn }}`)"
traefik.http.routers.tower01.middlewares: "https-redirect@file"
traefik.http.routers.tower01-sec.entrypoints: "https"
traefik.http.routers.tower01-sec.rule: "Host(`{{ app_server_fqdn }}`)"
traefik.http.routers.tower01-sec.tls: "true"
traefik.http.routers.tower01-sec.tls.options: "myTLSOptions@file"
traefik.http.routers.tower01-sec.tls.certresolver: "le"
traefik.http.routers.tower01-sec.middlewares: "default-headers@file"
traefik.http.services.tower01.loadbalancer.server.port: "8052"

尽管如此,Ansible 不会处理键名中的 jinja 变量。

有什么想法吗?

【问题讨论】:

    标签: docker ansible jinja2 traefik ansible-template


    【解决方案1】:

    您需要使用字典。

    - name: Create Traefik labels's dictionary
      set_fact:
          my_labels: "{{ my_labels | default({}) | combine ({ item.key : item.value }) }}"
      with_items:
        - { 'key': 'traefik.enable' , 'value': 'true'}
        - { 'key': 'traefik.http.routers.{{ app_name }}.entrypoints' , 'value': 'http'}
        - { 'key': 'traefik.http.routers.{{ app_name }}.rule' , 'value': 'Host(`{{ app_server_fqdn }}`)'}
        - { 'key': 'traefik.http.routers.{{ app_name }}.middlewares' , 'value': 'https-redirect@file'}
        - ...
    

    并在 docker_container 中使用您的新字典:

    - name: "{{ app_name }} | create awx web container"
      docker_container:
        name:           "{{ app_name }}-web"
        hostname:       "awxweb"
        user:           "root"
        image:          "ansible/awx_web:{{ docker_image[loop_item] | default('latest') }}"
        env:            "{{ docker_env[loop_item] | default(omit) }}"
        networks:       [ name: "{{ app_name }}" ]
        purge_networks: true
        volumes:        "{{ docker_volumes[loop_item] | default(omit) }}"
        restart_policy: "unless-stopped"
        labels:         "{{ my_labels }}"
        state:          "{{ state | default('started') }}"
    

    使用循环,您可以创建不同的字典:https://www.middlewareinventory.com/blog/ansible-dict/

    【讨论】:

      【解决方案2】:

      您可以通过向 docker_container 任务提供变量来定义容器标签:

      ---
      - hosts: localhost
        gather_facts: false
        vars:
          app_server_fqdn: example.com
          app_names:
            - tower01
            - tower02
        tasks:
          - debug:
              msg: "{{ docker_labels }}"
            loop: "{{ app_names }}"
            vars:
              docker_labels: >-
                {{
                  {
                    "traefik.enable": "true",
                    "traefik.http.routers.{}.entrypoints".format(item): "http",
                    "traefik.http.routers.{}.rule".format(item): "Host(`{}`)".format(app_server_fqdn),
                    "traefik.http.routers.{}.middlewares".format(item): "https-redirect@file",
                    "traefik.http.routers.{}-sec.entrypoints".format(item): "https",
                    "traefik.http.routers.{}-sec.rule".format(item): "Host(`{}`)".format(app_server_fqdn),
                    "traefik.http.routers.{}-sec.tls".format(item): "true",
                    "traefik.http.routers.{}-sec.tls.options".format(item): "myTLSOptions@file",
                    "traefik.http.routers.{}-sec.tls.certresolver".format(item): "le",
                    "traefik.http.routers.{}-sec.middlewares".format(item): "default-headers@file",
                    "traefik.http.services.{}.loadbalancer.server.port".format(item): "8052"
                  }
                }}
      

      在这种情况下,您可以为应用使用其他过滤器(例如三元)和更复杂的数据:

      ---
      - hosts: localhost
        gather_facts: false
        vars:
          app_server_fqdn: example.com
          app_names:
            - name: tower01
              port: 8052
            - name: tower02
              port: 8053
            - name: tower03
      
        tasks:
          - debug:
              msg: "{{ docker_labels }}"
            loop: "{{ app_names }}"
            loop_control:
              loop_var: app
              label: "{{ app.name }}"
            vars:
              docker_labels: >-
                {{
                  {
                    "traefik.enable": "true",
                    "traefik.http.routers.{}.entrypoints".format(app.name): "http",
                    "traefik.http.routers.{}.rule".format(app.name): "Host(`{}`)".format(app_server_fqdn),
                    "traefik.http.routers.{}.middlewares".format(app.name): "https-redirect@file",
                    "traefik.http.routers.{}-sec.entrypoints".format(app.name): "https",
                    "traefik.http.routers.{}-sec.rule".format(app.name): "Host(`{}`)".format(app_server_fqdn),
                    "traefik.http.routers.{}-sec.tls".format(app.name): "true",
                    "traefik.http.routers.{}-sec.tls.options".format(app.name): "myTLSOptions@file",
                    "traefik.http.routers.{}-sec.tls.certresolver".format(app.name): "le",
                    "traefik.http.routers.{}-sec.middlewares".format(app.name): "default-headers@file"
                  } | combine(
                        (app.port is defined) | ternary(
                          {'traefik.http.services.{}.loadbalancer.server.port'.format(app.name): app.port}, {}
                        )
                      )
                }}
      

      结果:

      TASK [debug] ********************************************************************************************************************************************************************************************************************
      ok: [localhost] => (item=tower01) => 
        msg:
          traefik.enable: 'true'
          traefik.http.routers.tower01-sec.entrypoints: https
          traefik.http.routers.tower01-sec.middlewares: default-headers@file
          traefik.http.routers.tower01-sec.rule: Host(`example.com`)
          traefik.http.routers.tower01-sec.tls: 'true'
          traefik.http.routers.tower01-sec.tls.certresolver: le
          traefik.http.routers.tower01-sec.tls.options: myTLSOptions@file
          traefik.http.routers.tower01.entrypoints: http
          traefik.http.routers.tower01.middlewares: https-redirect@file
          traefik.http.routers.tower01.rule: Host(`example.com`)
          traefik.http.services.tower01.loadbalancer.server.port: 8052
      ok: [localhost] => (item=tower02) => 
        msg:
          traefik.enable: 'true'
          traefik.http.routers.tower02-sec.entrypoints: https
          traefik.http.routers.tower02-sec.middlewares: default-headers@file
          traefik.http.routers.tower02-sec.rule: Host(`example.com`)
          traefik.http.routers.tower02-sec.tls: 'true'
          traefik.http.routers.tower02-sec.tls.certresolver: le
          traefik.http.routers.tower02-sec.tls.options: myTLSOptions@file
          traefik.http.routers.tower02.entrypoints: http
          traefik.http.routers.tower02.middlewares: https-redirect@file
          traefik.http.routers.tower02.rule: Host(`example.com`)
          traefik.http.services.tower02.loadbalancer.server.port: 8053
      ok: [localhost] => (item=tower03) => 
        msg:
          traefik.enable: 'true'
          traefik.http.routers.tower03-sec.entrypoints: https
          traefik.http.routers.tower03-sec.middlewares: default-headers@file
          traefik.http.routers.tower03-sec.rule: Host(`example.com`)
          traefik.http.routers.tower03-sec.tls: 'true'
          traefik.http.routers.tower03-sec.tls.certresolver: le
          traefik.http.routers.tower03-sec.tls.options: myTLSOptions@file
          traefik.http.routers.tower03.entrypoints: http
          traefik.http.routers.tower03.middlewares: https-redirect@file
          traefik.http.routers.tower03.rule: Host(`example.com`)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多