├── .ansible-lint ├── .gitignore ├── .pre-commit-config.yaml ├── all.yml ├── group_vars └── all │ ├── vars.yml │ └── vault.yml ├── inventory └── cluster ├── requirements.yml └── roles ├── build ├── defaults │ └── main.yml ├── meta │ └── main.yml └── tasks │ └── main.yml ├── deploy ├── meta │ └── main.yml ├── services │ ├── api │ │ ├── .env.j2 │ │ └── service.yml │ ├── app │ │ └── service.yml │ ├── config-create.yml │ ├── config.yml │ ├── converter │ │ ├── .env.j2 │ │ └── service.yml │ ├── nginx │ │ ├── nginx.conf.j2 │ │ └── service.yml │ ├── rmq │ │ └── service.yml │ ├── secret-create.yml │ └── secret.yml ├── tasks │ └── main.yml └── vars │ └── main.yml ├── preconfig ├── meta │ └── main.yml └── tasks │ └── main.yml ├── swarm_init ├── meta │ └── main.yml └── tasks │ └── main.yml ├── swarm_join ├── meta │ └── main.yml └── tasks │ └── main.yml └── swarm_leave ├── meta └── main.yml └── tasks └── main.yml /.ansible-lint: -------------------------------------------------------------------------------- 1 | exclude_paths: 2 | - .github/ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_store 2 | .pass 3 | /tokens -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/ansible-community/ansible-lint.git 3 | rev: v5.1.0a1 4 | hooks: 5 | - id: ansible-lint 6 | files: \.(yaml|yml)$ 7 | -------------------------------------------------------------------------------- /all.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Deploy / build server 3 | hosts: deploy 4 | roles: 5 | - role: preconfig 6 | tags: preconfig 7 | - role: build 8 | tags: build 9 | - role: deploy 10 | tags: deploy 11 | - role: swarm_init 12 | tags: swarm_init 13 | - role: swarm_leave 14 | node_name: server2 15 | tags: swarm_leave 16 | 17 | - name: Manager 18 | hosts: managers 19 | roles: 20 | - role: preconfig 21 | tags: preconfig 22 | - role: swarm_join 23 | type: manager 24 | tags: swarm_join 25 | 26 | - name: Worker 27 | hosts: workers 28 | roles: 29 | - role: preconfig 30 | tags: preconfig 31 | - role: swarm_join 32 | type: worker 33 | tags: swarm_join 34 | -------------------------------------------------------------------------------- /group_vars/all/vars.yml: -------------------------------------------------------------------------------- 1 | --- 2 | rmq_defaults: 3 | - name: AMQP_EXCHANGE 4 | value: xchg_integrations 5 | - name: AMQP_USER 6 | value: "{{rmq.user}}" 7 | - name: AMQP_PASSWORD 8 | value: "{{rmq.password}}" 9 | - name: AMQP_HOSTNAME 10 | value: rmq 11 | 12 | registry_name: "localhost:5000/" 13 | 14 | services: 15 | - name: api 16 | version: latest 17 | - name: app 18 | version: latest 19 | - name: converter 20 | version: latest 21 | - name: rmq 22 | version: 3-management 23 | - name: nginx 24 | version: latest 25 | 26 | non_build_services: 27 | - name: rmq 28 | version: 3-management 29 | - name: nginx 30 | version: latest 31 | 32 | configs: 33 | converter: 34 | queue: q_imageProcessor 35 | 36 | advertise_addr: 10.11.10.1 37 | -------------------------------------------------------------------------------- /group_vars/all/vault.yml: -------------------------------------------------------------------------------- 1 | --- 2 | rmq: 3 | user: admin 4 | password: admin 5 | -------------------------------------------------------------------------------- /inventory/cluster: -------------------------------------------------------------------------------- 1 | [deploy] 2 | server1 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2223 3 | 4 | [managers] 5 | server2 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2224 6 | server3 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2225 7 | 8 | [workers] 9 | server4 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2226 10 | server5 ansible_host=127.0.0.1 ansible_user=vagrant ansible_port=2227 -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | collections: 2 | - name: community.docker 3 | -------------------------------------------------------------------------------- /roles/build/defaults/main.yml: -------------------------------------------------------------------------------- 1 | git_folder: /home/vagrant/docker 2 | -------------------------------------------------------------------------------- /roles/build/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: build 3 | description: Сборка монорепозитория 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/build/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Клонируем репозиторий 3 | ansible.builtin.git: 4 | repo: "https://github.com/AlariCode/docker-demo.git" 5 | dest: "{{ git_folder }}" 6 | version: block-14 7 | 8 | - name: Собираем image 9 | community.docker.docker_image: 10 | name: "{{ registry_name }}{{ item.name }}" 11 | tag: "{{ item.version }}" 12 | push: true 13 | force_source: true 14 | force_tag: true 15 | build: 16 | path: "{{ git_folder }}" 17 | dockerfile: "{{ git_folder }}/apps/{{ item.name }}/Dockerfile" 18 | source: build 19 | loop: "{{ services | difference(non_build_services) }}" 20 | 21 | - name: Удаляем репозиторий 22 | file: 23 | state: absent 24 | path: "{{ git_folder }}" 25 | -------------------------------------------------------------------------------- /roles/deploy/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: deploy 3 | description: Выкладка микросервисов на docker кластер 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/deploy/services/api/.env.j2: -------------------------------------------------------------------------------- 1 | {% for item in rmq_defaults %} 2 | {{ item.name }}={{ item.value }} 3 | {% endfor %} -------------------------------------------------------------------------------- /roles/deploy/services/api/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Конфигурация секрета" 3 | include: "../secret.yml" 4 | 5 | - name: "[{{ name }}] Выкладка сервиса" 6 | block: 7 | - name: "[{{ name }}] Выкладываем сервис" 8 | community.docker.docker_swarm_service: 9 | name: "{{ name }}" 10 | image: "{{ registry_name }}{{ name }}:{{ version }}" 11 | state: present 12 | force_update: true 13 | networks: 14 | - name: "{{ network_name }}" 15 | publish: 16 | - mode: ingress 17 | protocol: tcp 18 | published_port: 3002 19 | target_port: 3000 20 | secrets: 21 | - secret_name: "{{ name }}.env" 22 | filename: "/opt/app/.env" 23 | tags: "{{ name }}" 24 | -------------------------------------------------------------------------------- /roles/deploy/services/app/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Выкладка сервиса" 3 | block: 4 | - name: "[{{ name }}] Выкладываем сервис" 5 | community.docker.docker_swarm_service: 6 | name: "{{ name }}" 7 | image: "{{ registry_name }}{{ name }}:{{ version }}" 8 | state: present 9 | force_update: true 10 | networks: 11 | - name: "{{ network_name }}" 12 | publish: 13 | - mode: ingress 14 | protocol: tcp 15 | published_port: 3001 16 | target_port: 80 17 | tags: "{{ name }}" 18 | -------------------------------------------------------------------------------- /roles/deploy/services/config-create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Создаём конфиг" 3 | vars: 4 | config_file: "{{ lookup('template', '{{ name }}/{{ config_item }}.j2') }}" 5 | community.docker.docker_config: 6 | name: "{{ config_item }}" 7 | data: "{{ config_file | b64encode }}" 8 | labels: 9 | config: "{{ config_file | hash('sha1') }}" 10 | data_is_b64: true 11 | state: present 12 | -------------------------------------------------------------------------------- /roles/deploy/services/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Конфигурация конфига" 3 | block: 4 | - name: "[{{ name }}] Создаём конфиг" 5 | include: "config-create.yml" 6 | tags: "{{ name }}" 7 | 8 | rescue: 9 | - name: "[{{ name }}] Удаляем сервис" 10 | community.docker.docker_swarm_service: 11 | name: "{{ name }}" 12 | state: absent 13 | 14 | - name: "[{{ name }}] Создаём конфиг" 15 | include: "config-create.yml" 16 | -------------------------------------------------------------------------------- /roles/deploy/services/converter/.env.j2: -------------------------------------------------------------------------------- 1 | {% for item in rmq_defaults %} 2 | {{ item.name }}={{ item.value }} 3 | {% endfor %} 4 | AMQP_QUEUE={{ configs.converter.queue }} -------------------------------------------------------------------------------- /roles/deploy/services/converter/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Конфигурация секрета" 3 | include: "../secret.yml" 4 | 5 | - name: "[{{ name }}] Выкладка сервиса" 6 | block: 7 | - name: "[{{ name }}] Выкладываем сервис" 8 | community.docker.docker_swarm_service: 9 | name: "{{ name }}" 10 | image: "{{ registry_name }}{{ name }}:{{ version }}" 11 | state: present 12 | force_update: true 13 | networks: 14 | - name: "{{ network_name }}" 15 | secrets: 16 | - secret_name: "{{ name }}.env" 17 | filename: "/opt/app/.env" 18 | tags: "{{ name }}" 19 | -------------------------------------------------------------------------------- /roles/deploy/services/nginx/nginx.conf.j2: -------------------------------------------------------------------------------- 1 | worker_processes 2; 2 | 3 | events { worker_connections 1024; } 4 | 5 | http { 6 | server { 7 | listen 80; 8 | server_name image.local; 9 | 10 | location ~ (/uploads/|/upload) { 11 | proxy_pass http://api:3000; 12 | } 13 | 14 | location ~ (/) { 15 | proxy_pass http://app; 16 | } 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /roles/deploy/services/nginx/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Конфигурация конфига" 3 | include: "../config.yml" 4 | loop: 5 | - nginx.conf 6 | loop_control: 7 | loop_var: config_item 8 | 9 | - name: "[{{ name }}] Выкладка сервиса" 10 | block: 11 | - name: "[{{ name }}] Выкладываем сервис" 12 | community.docker.docker_swarm_service: 13 | name: "{{ name }}" 14 | image: "nginx:{{ version }}" 15 | state: present 16 | networks: 17 | - name: "{{ network_name }}" 18 | publish: 19 | - mode: ingress 20 | protocol: tcp 21 | published_port: 80 22 | target_port: 80 23 | configs: 24 | - config_name: nginx.conf 25 | filename: "/etc/nginx/nginx.conf" 26 | tags: "{{ name }}" 27 | -------------------------------------------------------------------------------- /roles/deploy/services/rmq/service.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Выкладка сервиса" 3 | block: 4 | - name: "[{{ name }}] Выкладываем сервис" 5 | community.docker.docker_swarm_service: 6 | name: "{{ name }}" 7 | image: "rabbitmq:{{ version }}" 8 | state: present 9 | networks: 10 | - name: "{{ network_name }}" 11 | env: 12 | - RABBITMQ_DEFAULT_USER={{ rmq.user }} 13 | - RABBITMQ_DEFAULT_PASS={{ rmq.password }} 14 | tags: "{{ name }}" 15 | -------------------------------------------------------------------------------- /roles/deploy/services/secret-create.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Создаём секрет" 3 | vars: 4 | env_file: "{{ lookup('template', '{{ name }}/.env.j2') }}" 5 | community.docker.docker_secret: 6 | name: "{{ name }}.env" 7 | data: "{{ env_file | b64encode }}" 8 | labels: 9 | secret: "{{ env_file | hash('sha1') }}" 10 | data_is_b64: true 11 | state: present 12 | -------------------------------------------------------------------------------- /roles/deploy/services/secret.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "[{{ name }}] Конфигурация секрета" 3 | block: 4 | - name: "[{{ name }}] Создаём секрет" 5 | include: "secret-create.yml" 6 | tags: "{{ name }}" 7 | 8 | rescue: 9 | - name: "[{{ name }}] Удаляем сервис" 10 | community.docker.docker_swarm_service: 11 | name: "{{ name }}" 12 | state: absent 13 | 14 | - name: "[{{ name }}] Создаём секрет" 15 | include: "secret-create.yml" 16 | -------------------------------------------------------------------------------- /roles/deploy/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Создание сети 3 | community.docker.docker_network: 4 | name: "{{ network_name }}" 5 | driver: overlay 6 | 7 | - name: Выкладка сервисов 8 | include: "../services/{{ item.name }}/service.yml" 9 | vars: 10 | - name: "{{ item.name }}" 11 | - version: "{{ item.version }}" 12 | loop: "{{ services }}" 13 | -------------------------------------------------------------------------------- /roles/deploy/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | network_name: app_network 3 | -------------------------------------------------------------------------------- /roles/preconfig/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: preconfig 3 | description: Настройка серверов для работы с Docker 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/preconfig/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Утановка Docker 3 | block: 4 | - name: Добавляем universe 5 | apt_repository: 6 | repo: "deb http://us.archive.ubuntu.com/ubuntu/ {{ ansible_distribution_release }} universe" 7 | state: present 8 | 9 | - name: Установка дополнительных пакетов 10 | apt: 11 | name: 12 | - apt-transport-https 13 | - ca-certificates 14 | - curl 15 | - gnupg 16 | - lsb-release 17 | - python3-pip 18 | update-cache: true 19 | cache_valid_time: 86400 20 | 21 | - name: Добавление ключа Docker 22 | apt_key: 23 | url: https://download.docker.com/linux/ubuntu/gpg 24 | state: present 25 | keyring: /usr/share/keyrings/docker-archive-keyring.gpg 26 | 27 | - name: Установка стабильного репозитория 28 | apt_repository: 29 | repo: > 30 | deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] 31 | https://download.docker.com/linux/ubuntu 32 | {{ ansible_distribution_release }} stable 33 | state: present 34 | update-cache: true 35 | filename: docker 36 | 37 | - name: Установка Docker-ce 38 | apt: 39 | name: docker-ce 40 | update-cache: true 41 | 42 | - name: Проверка что Docker установлен и перезагружен 43 | service: 44 | name: docker 45 | state: restarted 46 | enabled: true 47 | become: true 48 | 49 | - name: Установка Docker-compose 50 | block: 51 | - name: Получение последней версии Docker-compose 52 | uri: 53 | url: https://api.github.com/repos/docker/compose/releases/latest 54 | body_format: json 55 | register: page 56 | 57 | - name: Установка Docker-compose 58 | get_url: 59 | url: "https://github.com/docker/compose/releases/download/{{ page.json.tag_name }}/docker-compose-Linux-x86_64" 60 | dest: /usr/local/bin/docker-compose 61 | mode: 0755 62 | become: true 63 | 64 | - name: Настройка дополнительных пакетов python 65 | block: 66 | - name: Установка pip пакетов 67 | pip: 68 | name: docker 69 | 70 | - name: Завершение установки 71 | block: 72 | - name: Добавление пользователя в группу Docker 73 | user: 74 | name: "{{ ansible_user }}" 75 | groups: docker 76 | append: true 77 | 78 | - name: Перезагрузка 79 | reboot: 80 | become: true 81 | -------------------------------------------------------------------------------- /roles/swarm_init/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: swarm_init 3 | description: Инициализация кластера swarm 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/swarm_init/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Инициализация swarm 3 | community.docker.docker_swarm: 4 | state: present 5 | advertise_addr: "{{ advertise_addr }}" 6 | register: token 7 | 8 | - name: Сохранение токенов 9 | set_fact: 10 | token_manager: "{{ token.swarm_facts.JoinTokens.Manager }}" 11 | token_worker: "{{ token.swarm_facts.JoinTokens.Worker }}" 12 | cacheable: true 13 | -------------------------------------------------------------------------------- /roles/swarm_join/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: swarm_join 3 | description: Присоединение к swarm 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/swarm_join/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Подключение 3 | community.docker.docker_swarm: 4 | state: join 5 | remote_addrs: "{{ advertise_addr }}" 6 | join_token: > 7 | {{ 8 | hostvars['server1']['ansible_facts']['token_worker'] 9 | if type == 'worker' else 10 | hostvars['server1']['ansible_facts']['token_manager'] 11 | }} 12 | -------------------------------------------------------------------------------- /roles/swarm_leave/meta/main.yml: -------------------------------------------------------------------------------- 1 | galaxy_info: 2 | role_name: swarm_leave 3 | description: Удаление ноды из swarm 4 | author: Anton Larichev 5 | license: MIT 6 | min_ansible_version: 2.9 7 | platforms: 8 | - name: Ubuntu 9 | versions: 10 | - all 11 | -------------------------------------------------------------------------------- /roles/swarm_leave/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Перевод в статус drain 3 | community.docker.docker_node: 4 | hostname: "{{ node_name }}" 5 | availability: drain 6 | 7 | - name: Ожидание остановки 8 | community.docker.docker_host_info: 9 | containers: true 10 | register: result 11 | retries: 30 12 | delay: 2 13 | until: result.host_info.ContainersRunning == 0 14 | delegate_to: "{{ node_name }}" 15 | 16 | - name: Удаление ноды 17 | command: "docker node rm {{ node_name }} --force" --------------------------------------------------------------------------------