Применение DRY к docker-compose.yml

Apr 2, 2018 07:50 · 813 words · 4 minute read docker docker-compose

Мы уже знаем, что файлы docker-compose.yml - отличный способ определения нескольких сервисов (контейнеров), которые должны работать как единый стек. Но при большом количестве сервисов в файле неизменно появляются одинаковые, повторяющиеся для каждого контейнера блоки кода (описания) - давайте разберемся с ними!

Давайте применим принцип Don’t Repeat Yourself (DRY) к файлам docker-compose.yml с использованием алиасов (aliases) и якорей (aliases) - встроенного функционала YAML.

С помощью якоря можно определить элемент в документе YAML, а затем ссылаться на этот элемент (используя алиас) позже в том же документе. Якорь можно обозначить с помощью символа &, алиас - с помощью символа *. Ниже приведен пример YAML-файла с якорем и алиасом:

base: &base
  name: Everyone has same name

foo:
  <<: *base
  age: 10

bar:
  <<: *base
  age: 20

После прочтения файла парсером YAML результат будет следующим:

foo:
  name: Everyone has same name
  age: 10

bar:
  name: Everyone has same name
  age: 20

Использование якорей и алиасов “в чистом” виде в конфигурационных файлах docker-compose.yml ранее было несколько неудобным и неочевидным, однако начиная с версии 3.4 добавлена поддержка расширенных полей (или полей расширений - extension fields). Теперь любой ключ верхнего уровня, начинающийся с x- в файле docker-compose.yml, будет проигнорирован утилитой docker-compose и самим Docker Engine. Такие расширения можно использовать для определения части сервиса, содержащей только общие параметры.

Рассмотрим конкретный пример. Ранее файле docker-compose.yml, описывающий стек сервисов для деплоя в docker swarm (подробнее здесь, здесь и тут) выглядел так:

version: '3.1'
services:
### PHP-FPM ########################################################
  php-fpm:
    image: registry.gitlab.lc:5000/develop/ed/php-fpm-ed-sq:staging
    volumes:
      - developcode:/var/www/develop
      - static:/var/www/static
    deploy:
      replicas: 4
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
    logging:
      driver: gelf
      options:
        gelf-address: "udp://${GRAYLOG_ADDR}:12201"
        tag: "php-fpm"
### Nginx ##########################################################
  nginx:
    image: registry.gitlab.lc:5000/develop/ed/nginx-ed-sq:staging
    volumes:
      - developcode:/var/www/develop
      - static:/var/www/static
    ports:
      - "80:80"
      - "443:443"
    deploy:
      replicas: 4
      update_config:
        parallelism: 1
        delay: 10s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
### SDCV ###########################################################
  sdcv:
    image: registry.gitlab.lc:5000/develop/ed/sdcv-ed-sq:latest
    ports:
      - "9095:9095"
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 1s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
    logging:
      driver: gelf
      options:
        gelf-address: "udp://${GRAYLOG_ADDR}:12201"
        tag: "sdcv"
### Redis ##########################################################
  redis:
    image: registry.gitlab.lc:5000/develop/ed/redis-ed-sq:latest
    volumes:
      - redis:/data
    ports:
      - "6379:6379"
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 1s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
    logging:
      driver: gelf
      options:
        gelf-address: "udp://${GRAYLOG_ADDR}:12201"
        tag: "redis"
### Memcached ######################################################
  memcached:
    image: registry.gitlab.lc:5000/develop/ed/memcached-ed-sq:latest
    volumes:
      - memcached:/var/lib/memcached
    ports:
      - "11211:11211"
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 1s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
    logging:
      driver: gelf
      options:
        gelf-address: "udp://${GRAYLOG_ADDR}:12201"
        tag: "memcached"
### Websocket ######################################################
  websocket:
    image: registry.gitlab.lc:5000/develop/ed/websocket-ed-sq:latest
    env_file: .env.staging.lc
    ports:
      - "8092:8092"
    deploy:
      replicas: 1
      update_config:
        parallelism: 1
        delay: 1s
      restart_policy:
        condition: on-failure
      placement:
        constraints: [node.role == manager]
    logging:
      driver: gelf
      options:
        gelf-address: "udp://${GRAYLOG_ADDR}:12201"
        tag: "websocket"
### Monitoring: node-exporter ######################################
  nodeexporter:
    image: prom/node-exporter:v0.14.0
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '-collector.procfs=/host/proc'
      - '-collector.sysfs=/host/sys'
      - '-collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
    labels:
      org.label-schema.group: "monitoring"
### Monitoring: cAdvisor ###########################################
  cadvisor:
    image: google/cadvisor:v0.26.1
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "9200:8080"
    deploy:
      mode: global
      restart_policy:
        condition: on-failure
    labels:
      org.label-schema.group: "monitoring"
### Volumes Setup ##################################################
volumes:
  developcode:
    external:
      name: code-${VER}
  memcached:
    driver: "local"
  redis:
    driver: "local"
  static:
    driver: "local"
    driver_opts:
      type: nfs
      o: addr=192.168.0.218,rw
      device: ":/srv/static"

Применяя принцип DRY данный файл получилось привести к следующему виду:

version: '3.4'
# Global logging options
# Customizing TAG: https://docs.docker.com/config/containers/logging/log_tags/
x-logging: &logging
  logging:
    driver: gelf
    options:
      gelf-address: "udp://${GRAYLOG_ADDR:-graylog.lc}:12201"
      tag: "{{.Name}}"
x-deploy-tmpl: &deploy-tmpl
  deploy:
    replicas: 1
    update_config:
      parallelism: 1
      delay: 1s
    restart_policy:
      condition: on-failure
    placement:
      constraints: [node.role == manager]
x-deploy-repl: &deploy-repl
  deploy:
    replicas: 4
    update_config:
      parallelism: 1
      delay: 1s
    restart_policy:
      condition: on-failure
    placement:
      constraints: [node.role == manager]
x-monitoring-tmpl: &monitoring-tmpl
  deploy:
    mode: global
    restart_policy:
      condition: on-failure
  labels:
    org.label-schema.group: "monitoring"
services:
### PHP-FPM ########################################################
  php-fpm:
    image: registry.gitlab.lc:5000/develop/ed/php-fpm-ed-sq:staging
    volumes:
      - developcode:/var/www/develop
      - static:/var/www/static
    <<: *deploy-repl
    <<: *logging
### Nginx ##########################################################
  nginx:
    image: registry.gitlab.lc:5000/develop/ed/nginx-ed-sq:staging
    volumes:
      - developcode:/var/www/develop
      - static:/var/www/static
    ports:
      - "80:80"
      - "443:443"
    <<: *deploy-repl
### SDCV ###########################################################
  sdcv:
    image: registry.gitlab.lc:5000/develop/ed/sdcv-ed-sq:latest
    ports:
      - "9095:9095"
    <<: *deploy-tmpl
    <<: *logging
### Redis ##########################################################
  redis:
    image: redis:4.0-alpine
    command:
      - 'redis-server'
      - '--loglevel ${REDIS_LOGLEVEL:-warning}'
      - '--databases 2'
      - '--save 300 1'
      - '--save 60 1000'
      - '--maxmemory ${REDIS_MAXMEM:-50mb}'
      - '--maxmemory-policy ${REDIS_POLICY:-noeviction}'
      - '--requirepass ${REDIS_PASS}'
    volumes:
      - redis:/data
    ports:
      - "6379:6379"
    <<: *deploy-tmpl
    <<: *logging
### Memcached ######################################################
  memcached:
    image: memcached:1.5-alpine
    volumes:
      - memcached:/var/lib/memcached
    ports:
      - "11211:11211"
    <<: *deploy-tmpl
    <<: *logging
### Websocket ######################################################
  websocket:
    image: registry.gitlab.lc:5000/develop/ed/websocket-ed-sq:latest
    env_file: .env.staging.lc
    ports:
      - "8092:8092"
    <<: *logging
### Monitoring: node-exporter ######################################
  nodeexporter:
    image: prom/node-exporter:v0.15.2
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
    ports:
      - "9100:9100"
    <<: *monitoring-tmpl
### Monitoring: cAdvisor ###########################################
  cadvisor:
    image: google/cadvisor:v0.29.0
    volumes:
      - /:/rootfs:ro
      - /var/run:/var/run:rw
      - /sys:/sys:ro
      - /var/lib/docker/:/var/lib/docker:ro
    ports:
      - "9200:8080"
    <<: *monitoring-tmpl
### Volumes Setup ##################################################
volumes:
  developcode:
    external:
      name: code-${VER}
  memcached:
    driver: "local"
  redis:
    driver: "local"
  static:
    driver: "local"
    driver_opts:
      type: nfs
      o: addr=192.168.0.218,rw
      device: ":/srv/static"

При упрощении своих конфигурационных файлов docker-compose.yml не забывайте проверять их синтаксис используя команду docker-compose config, как я уже советовал ранее.

tweet Share