Skip to content

Djuuu/ansible-role-docker-project

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Ansible Role: Docker-project

Base role for Docker Compose projects.

Requirements

  • Docker CLI with Docker compose plugin 2.18.0 or later
  • Ansible >=2.11.0

Role Variables

Common Docker projects variables:

Project name

docker_project_name: # example-project

Project name should be set in concrete roles using this role as a base.

This variable is derived into the following 2 variables:

  • docker_project_slug (slugified project name, with - separators)
    Determines:
    • directory where project will be installed
    • default service subdomain
    • misc. Traefik keys (service & router, middleware prefix)
  • docker_project_prefix (slugified project name, with _ separators)
    Used as dynamic variables prefix

Implementation example:

  • example-role/defaults/main.yml
    example_role_project_name: example
  • example-role/vars/main.yml
    docker_project_name: "{{ example_role_project_name }}"

Base directory for Docker projects

docker_projects_path: # /var/apps

Base domain suffixes

# Local machine domain
local_base_domain: internal

# Exposed service domain
exposed_base_domain: # example.net

These domains suffixes are used to build Traefik default rule in djuuu.traefik_docker, along with optional {{ docker_project_prefix }}_traefik_subdomain dynamic variable.

See:

Additional allowed origins

docker_project_allowed_origins: []
#  - https://dashboard.example.net

Used in csp-add-frame-ancestors@file and {{ docker_project_slug }}-cors@docker middlewares from djuuu.traefik_docker role.

Dynamic variables

Variables constructed from docker_project_name value can be used to configure:

  • {{ docker_project_prefix }}_restart
    Container restart policy (default: "unless-stopped")
  • Traefik integration (see djuuu.traefik_docker role)

    • {{ docker_project_prefix }}_traefik_enable
      Should Traefik expose service? (default: false)

    • {{ docker_project_prefix }}_traefik_domain
      Domain used to expose service (note: takes precedence over _traefik_subdomain)

    • {{ docker_project_prefix }}_traefik_subdomain
      Subdomain used to expose service (concatenated with local_base_domain / exposed_base_domain).

    • {{ docker_project_prefix }}_traefik_router_service
      Service name targeted by Traefik router

    • {{ docker_project_prefix }}_traefik_loadbalancer_server_port
      Port targeted by Traefik router

    • {{ docker_project_prefix }}_traefik_loadbalancer_server_scheme (default: "http")
      Scheme targeted by Traefik router

    • {{ docker_project_prefix }}_traefik_entrypoints (default: "https")
      Traefik router entrypoints

    • {{ docker_project_prefix }}_traefik_middlewares
      Traefik router middlewares

    • {{ docker_project_prefix }}_traefik_define_internal_route (default: false)
      Should an internal route be defined (restricted to traefik_internal_networks)

    • {{ docker_project_prefix }}_traefik_middlewares_internal
      Traefik router middlewares applied on internal route

    • {{ docker_project_prefix }}_access_control_max_age (default: 100)

    • {{ docker_project_prefix }}_access_control_allow_methods (default: "*")

    • {{ docker_project_prefix }}_access_control_allow_headers (default: "*")
      CORS settings when {{ docker_project_slug }}-cors@docker middleware is enabled

    • {{ docker_project_prefix }}_traefik_custom_labels
      Additional Traefik labels

  • Network

    • {{ docker_project_prefix }}_network_mode (default: bridge)
      Network mode (ex: host)
    • {{ docker_project_prefix }}_network_ipv4_subnet
    • {{ docker_project_prefix }}_network_ipv6_subnet
      Optional default network IP subnets
  • Additional docker compose options

    • {{ docker_project_prefix }}_service_additional_options
      Main service additional docker-compose options (ex: cpu_shares, deploy, ...)
    • {{ docker_project_prefix }}_service_additional_labels Main service additional docker-compose labels (ex: wud.tag.include, ...)
    • {{ docker_project_prefix }}_compose_additional_options
      Top-level additional docker-compose options

When set, dynamic variables are set into equivalent variables prefixed with docker_project_
(ex: docker_project_traefik_domain, docker_project_compose_additional_options, etc.)

Generated variables

These variables are computed from other variables and can be used in roles:

  • docker_project_path="{{ docker_projects_path }}/{{ docker_project_slug }}"
    Target directory of current project installation.
    Should be used in depending role.

  • traefik_domains
    list of fully qualified domains used to expose service (internal use)
    ex: ['hello-world.example.net', 'hello-world.local']

  • traefik_domain_label
    Traefik routing rule label when using domain configuration (internal use)
    ex: traefik.http.routers.hello-world.rule: Host(`hello-world.example.net`)

  • traefik_subdomain_label
    Traefik routing rule label when using subdomain configuration (internal use)
    ex: net.example.subdomain: hello-world

  • traefik_project_base_host_rules
    Host rules used in Traefik routing rules.
    Can be useful when adding custom routing rules ({{ docker_project_prefix }}_traefik_custom_labels)
    ex: (Host(`hello-world.example.net`) || Host(`hello-world.local`))

  • traefik_project_base_labels
    Generated Traefik labels.
    Should be added to the labels section of your service Docker Compose configuration.
    ex:

    traefik.enable: true  
    net.example.subdomain: hello-world  
    # ...  
  • docker_project_service_network_options
    Service network_mode or networks attributes.
    ex:

    network_mode: host # from `docker_project_network_mode` dynamic var

    or:

    networks:
      - default
      - other # from `docker_project_additional_networks` dynamic var
  • docker_project_default_network
    Generated default network configuration.
    Should be added to the networks section of your Docker Compose configuration.
    ex:

    default:  
      driver: bridge  
      ipam:  
        driver: default  
        config:  
          - subnet: 172.18.0.0/16  
          - subnet: 2001:db8:0001:0001::/64  
      enable_ipv6: true  

Other variables

# Path to the Docker CLI (Community.Docker modules argument)
# https://docs.ansible.com/ansible/latest/collections/community/docker/index.html
docker_cli:

docker_cmd computed variable is available for convenience.
It uses docker_cli if set, or defaults to 'docker'.

pull: false

Pulls image before starting container in compose-up task (intended as extra var).

Example role implementation

Role example:

  • hello_world/meta/main.yml
    galaxy_info:
      role_name: hello_world
    
    dependencies:
      - name: djuuu.docker_project
        src: https://github.com/Djuuu/ansible-role-docker-project
        version: main
  • hello_world/defaults/main.yml
    hello_world_project_name: hello-world
  • my-example/vars/main.yml
    docker_project_name: "{{ hello_world_project_name }}"
  • hello_world/tasks/main.yml
    ## Init
    - name: Ensure project directory exists
      ansible.builtin.file:
        path: "{{ docker_project_path }}"
        state: directory
        mode: '0755'
      tags: ["init"]
    
    ## Configure
    - name: Template docker-compose.yml
      ansible.builtin.template:
        src: docker-compose.yml.j2
        dest: "{{ docker_project_path }}/docker-compose.yml"
        mode: '0644'
        validate: "{{ docker_cmd }} compose -f %s config"
        backup: true
    
    ## Run
    - name: Start app
      ansible.builtin.include_role: { name: djuuu.docker_project, tasks_from: compose-up }
  • hello_world/templates/docker-compose.yml.j2
    name: {{ docker_project_slug }}
    
    services:
    
      hello_world:
        image: hello-world
        container_name: {{ docker_project_slug }}
        restart: {{ docker_project_restart }}
    
        {{ docker_project_service_network_options | indent(4) }}
    
        {{ docker_project_service_additional_options | indent(4) }}
    
        labels:
          {{ traefik_project_base_labels | indent(6) }}
          {{ docker_project_service_additional_labels | indent(6) }}
    
    {{ docker_project_networks }}
    
    {{ docker_project_compose_additional_options }}

Configuration example with dynamic vars:

  • host_vars/example/hello.yml
hello_world_project_name: "hey-there"

# Dynamic variables

hey_there_traefik_enable: true

hey_there_traefik_domain: example.net 
hey_there_traefik_subdomain: hey

hey_there_traefik_router_service: hello 
hey_there_traefik_loadbalancer_server_port: 1234 
hey_there_traefik_entrypoints: http,https
hey_there_traefik_middlewares: 
  - "internal-access@file"                  # see djuuu.traefik_docker templates/dynamic-conf/middlewares/internal-access.yml.j2
  - "csp-add-frame-ancestors@file"          # see djuuu.traefik_docker templates/dynamic-conf/middlewares/csp-add-frame-ancestors.yml.j2
  - "{{ docker_project_slug }}-cors@docker" # see tasks/_init_traefik_vars.yml
    
hey_there_access_control_max_age:       60
hey_there_access_control_allow_methods: "OPTIONS, HEAD, GET"
hey_there_access_control_allow_headers: "X-Custom-Header, Upgrade-Insecure-Requests"
  
hey_there_traefik_custom_labels: |-
  hello-label: hey there
  other-label: example

hey_there_network_mode: bridge

hey_there_additional_networks:
  - example_net
  
hey_there_network_ipv4_subnet: 172.18.0.0/16
hey_there_network_ipv6_subnet: 2001:db8:0001:0001::/64

hey_there_service_additional_options: |
  cpu_shares: 10
  deploy:
    resources:
      limits:
        memory: 128M
  ports:
    - "1234:1234"

hey_there_compose_additional_options: |
  x-example:
    title: This is an example

Dependencies

None.

Some variables allow integration with:

Example Playbooks

Role is not intended to be run as-is, but as a dependency in other roles.

However, there are some available tasks that can be used independently:

compose-ps

- name: List Docker Compose projects status
  hosts: all
  gather_facts: false

  vars:
    docker_projects:
      - my-project
      - other-project
    
  tasks:
    - name: Docker compose ps
      ansible.builtin.include_role:
        name: djuuu.docker_project
        tasks_from: compose-ps
      vars:
        docker_project_name: "{{ item.name | default(item) }}"
        project_restart: "{{ item.restart | default(true) }}"
      loop: "{{ docker_projects | default([]) }}"

compose-update

- name: Update Docker Compose projects
  hosts: all
  gather_facts: false

  vars:
    docker_projects:
      - "my-project"
      - { name: "other-project", restart: false } # on-demand service without running container

  tasks:

    - name: Docker compose update
      ansible.builtin.include_role:
        name: djuuu.docker_project
        tasks_from: compose-update
      vars:
        docker_project_name: "{{ item.name | default(item) }}"
        project_restart: "{{ item.restart | default(true) }}"
      loop: "{{ docker_projects | default([]) }}"

    - name: Docker system prune
      ansible.builtin.include_role:
        name: djuuu.docker_project
        tasks_from: system-prune

compose-up

- name: Start Docker Compose project
  hosts: example
  gather_facts: false
  vars:
    docker_project_name: my-project
  tasks:
    - name: Start app
      ansible.builtin.include_role:
        name: djuuu.docker_project
        tasks_from: compose-up

compose-restart

- name: Restart Docker Compose project
  hosts: example
  gather_facts: false
  vars:
    docker_project_name: my-project
  tasks:
    - name: Restart app
      ansible.builtin.include_role: 
        name: djuuu.docker_project
        tasks_from: compose-restart

system-prune

- name: Docker system prune
  hosts: all
  gather_facts: false
  tasks:
    - name: Docker system prune
      ansible.builtin.include_role:
        name: djuuu.docker_project
        tasks_from: system-prune

License

Beerware License

About

Base role for Docker Compose projects

Topics

Resources

License

Stars

Watchers

Forks