feat: add worker nodes to docker swarm setup

This commit is contained in:
Alexander Navarro 2024-12-10 16:26:17 -03:00
parent 22d7e4a318
commit d318880600
10 changed files with 252 additions and 112 deletions

View file

@ -1,5 +1,12 @@
[homelab]
[homelab:children]
docker
[docker:children]
docker_managers
docker_workers
[docker_managers]
10.0.10.50
[docker]
10.0.10.50 docker_swarm_manager=true
[docker_workers]
10.0.10.[51:52]

View file

@ -1,6 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/playbook.json
# > /COPILOT_GENERATE I'm writing an ansible playbook to setup a new alpine server, I want you to help me to generate some tasks
---
- name: Setup an alpine machine
hosts: homelab
user: root
@ -41,24 +41,12 @@
line: 'permit persist :wheel'
state: present
- name: Install Docker
ansible.builtin.package:
state: present
name:
- docker
- docker-cli-compose
- py3-yaml
- py3-pip
- py3-docker-py
- name: Common setup
hosts: homelab
user: root
roles:
- role: common
vars:
extra_groups:
- docker
robo_allowed_commands:
- "docker system dial-stdio"
@ -67,3 +55,27 @@
user: root
roles:
- docker
vars:
users:
- aleidk
- robo
- name: Setup docker swarm manager
hosts: docker_managers
user: root
tasks:
- name: Setup swarm manager
include_role:
name: docker
tasks_from: swarm_manager.yaml
- name: Setup docker swarm workers
hosts: docker_workers
user: root
tasks:
- name: "Setup swarm workers"
include_role:
name: docker
tasks_from: swarm_worker.yaml
vars:
managers_group: docker_managers

View file

@ -9,6 +9,7 @@ argument_specs:
type: "list"
elements: "str"
required: false
default: []
description:
- "Additional groups that will be added to each user"
robo_allowed_commands:

View file

@ -1,10 +1,5 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/tasks.json
- name: Create a user group named docker
loop: "{{ extra_groups }}"
ansible.builtin.group:
name: "{{ item }}"
- name: Setup users
loop: "{{ users }}"
ansible.builtin.user:
@ -14,7 +9,7 @@
shell: "{{ item.shell }}"
create_home: true
password: "{{ (item.password != '!' or item.password != '*') | ternary(item.password | password_hash('sha512'), item.password) }}"
groups: "{{ item.groups + extra_groups }}"
groups: "{{ item.groups + (extra_groups | default([])) }}"
- name: Add SSH public key to users
loop: "{{ users }}"

61
roles/docker/files/openrc.sh Executable file
View file

@ -0,0 +1,61 @@
#!/sbin/openrc-run
supervisor=supervise-daemon
name="Docker Daemon"
description="Persistent process that manages docker containers"
description_reload="Reload configuration without exiting"
command="${DOCKERD_BINARY:-/usr/bin/dockerd}"
command_args="${DOCKER_OPTS}"
DOCKER_LOGFILE="${DOCKER_LOGFILE:-/var/log/${RC_SVCNAME}.log}"
DOCKER_ERRFILE="${DOCKER_ERRFILE:-${DOCKER_LOGFILE}}"
DOCKER_OUTFILE="${DOCKER_OUTFILE:-${DOCKER_LOGFILE}}"
if [ "$DOCKER_ERRFILE" = "$DOCKER_OUTFILE" ]; then
LOGPROXY_OPTS="$LOGPROXY_OPTS -m"
fi
export \
LOGPROXY_CHMOD="${LOGPROXY_CHMOD:-0644}" \
LOGPROXY_LOG_DIRECTORY="${LOGPROXY_LOG_DIRECTORY:-/var/log}" \
LOGPROXY_ROTATION_SIZE="${LOGPROXY_ROTATION_SIZE:-104857600}" \
LOGPROXY_ROTATION_TIME="${LOGPROXY_ROTATION_TIME:-86400}" \
LOGPROXY_ROTATION_SUFFIX="${LOGPROXY_ROTATION_SUFFIX:-.%Y%m%d%H%M%S}" \
LOGPROXY_ROTATED_FILES="${LOGPROXY_ROTATE_FILES:-5}"
output_logger="log_proxy $LOGPROXY_OPTS $DOCKER_OUTFILE"
error_logger="log_proxy $LOGPROXY_OPTS $DOCKER_ERRFILE"
extra_started_commands="reload"
rc_ulimit=""
RC_ULIMIT=""
if [ "$1" = "start" ]; then
if [ $BASH ]; then
rc_ulimit="${DOCKER_ULIMIT:--c unlimited -n 1048576 -u unlimited}"
else
ulimit -c unlimited
ulimit -n 1048576
ulimit -p unlimited
fi
fi
retry="${DOCKER_RETRY:-TERM/60/KILL/10}"
if [ -e /etc/profile.d/proxy.sh ]; then
. /etc/profile.d/proxy.sh
fi
depend() {
need sysfs cgroups net
after firewall
}
start_pre() {
checkpath -f -m 0644 -o root:docker "$DOCKER_ERRFILE" "$DOCKER_OUTFILE"
}
reload() {
ebegin "Reloading configuration"
$supervisor $RC_SVCNAME --signal HUP
eend $?
}

View file

@ -0,0 +1,25 @@
---
argument_specs:
main:
short_description: Main entrypoint
author:
- aleidk
options:
users:
type: "list"
elements: "str"
default: []
description:
- "list of users to add to the docker group"
swarm_workers:
short_description: Docker swarm workers setup
author:
- aleidk
options:
managers_group:
type: "str"
required: true
description:
- "The host group of the managers"
- "Used to obtain the advertised address and join tokens"

View file

@ -0,0 +1,20 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/tasks.json
---
- name: Install Docker
ansible.builtin.package:
state: present
name:
- docker
- docker-cli-compose
- py3-yaml
- py3-pip
- py3-docker-py
- name: Copy openrc.sh to /etc/init.d/docker
copy:
src: files/openrc.sh
dest: /etc/init.d/docker
mode: '0755'
owner: root
group: root

View file

@ -1,94 +1,23 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/tasks.json
---
- name: Create a user group named docker
ansible.builtin.group:
name: "docker"
- name: Add users to docker group
loop: "{{ users }}"
ansible.builtin.user:
state: present
append: true
name: "{{ item }}"
groups: "docker"
- name: Install docker in Alpine
import_tasks: docker_alpine.yaml
when: ansible_facts['os_family']|lower == 'alpine'
- name: Start docker service
ansible.builtin.service:
name: docker
state: started
enabled: true
- name: Setup Docker Swarm
when: docker_swarm_manager | bool
block:
- name: Enable Docker Swarm mode
community.docker.docker_swarm:
state: present
- name: Create Traefik network
community.docker.docker_network:
name: reverse-proxy
driver: overlay
attachable: true
- name: Deploy Traefik service
community.docker.docker_compose_v2:
remove_orphans: true
project_name: reverse-proxy
definition:
networks:
reverse-proxy:
external: true
services:
traefik:
container_name: traefix-proxy
image: 'traefik:latest'
restart: unless-stopped
networks:
- reverse-proxy
ports:
# listen on host ports without ingress network
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 8080
published: 8080
protocol: tcp
mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=true'
- '--entrypoints.http.address=:80'
- '--entryPoints.http.forwardedHeaders.trustedIPs=10.0.10.0/24'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=50'
# - "--providers.swarm.endpoint=tcp://{{ ansible_default_ipv4.address }}:2375"
- --providers.swarm.exposedByDefault=false
- --providers.swarm.network=reverse-proxy
deploy:
mode: global
placement:
constraints:
- node.role==manager
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080
- name: Check if Docker context exists
local_action: ansible.builtin.command docker context inspect {{ ansible_hostname }}
register: context_exists
ignore_errors: true
- name: Create Docker context for each Swarm manager machine
local_action: >
ansible.builtin.command docker context create {{ ansible_hostname }} --docker "host=ssh://{{ ansible_default_ipv4.address }}"
when: context_exists.stderr != ''
- name: Join Docker Swarm as a worker
community.docker.docker_swarm:
state: join
join_token: "{{ hostvars['manager']['docker_swarm_worker_token'] }}"
remote_addrs: ["{{ hostvars['manager']['ansible_default_ipv4']['address'] }}"]
when: not docker_swarm_manager | bool

View file

@ -0,0 +1,81 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/tasks.json
---
- name: Enable Docker Swarm mode
register: swarm_info
community.docker.docker_swarm:
state: present
- name: Create Traefik network
community.docker.docker_network:
name: reverse-proxy
driver: overlay
attachable: true
- name: Check if Docker context exists
local_action: ansible.builtin.command docker context inspect {{ ansible_hostname }}
register: context_exists
ignore_errors: true
- name: Create Docker context for each Swarm manager machine
local_action: >
ansible.builtin.command docker context create {{ ansible_hostname }} --docker "host=ssh://{{ ansible_default_ipv4.address }}"
when: context_exists.stderr != ''
- name: Deploy Traefik service
community.docker.docker_compose_v2:
remove_orphans: true
project_name: reverse-proxy
definition:
networks:
reverse-proxy:
external: true
services:
traefik:
container_name: traefix-proxy
image: 'traefik:latest'
restart: unless-stopped
networks:
- reverse-proxy
ports:
# listen on host ports without ingress network
- target: 80
published: 80
protocol: tcp
mode: host
- target: 443
published: 443
protocol: tcp
mode: host
- target: 8080
published: 8080
protocol: tcp
mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
healthcheck:
test: 'wget -qO- http://localhost:80/ping || exit 1'
interval: 4s
timeout: 2s
retries: 5
command:
- '--ping=true'
- '--ping.entrypoint=http'
- '--api.dashboard=true'
- '--api.insecure=true'
- '--entrypoints.http.address=:80'
- '--entryPoints.http.forwardedHeaders.trustedIPs=10.0.10.0/24'
- '--entrypoints.http.http.encodequerysemicolons=true'
- '--entryPoints.http.http2.maxConcurrentStreams=50'
# - "--providers.swarm.endpoint=tcp://{{ ansible_default_ipv4.address }}:2375"
- --providers.swarm.exposedByDefault=false
- --providers.swarm.network=reverse-proxy
deploy:
mode: global
placement:
constraints:
- node.role==manager
labels:
- traefik.enable=true
- traefik.http.routers.traefik.entrypoints=http
- traefik.http.routers.traefik.service=api@internal
- traefik.http.services.traefik.loadbalancer.server.port=8080

View file

@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ansible/ansible-lint/refs/heads/main/src/ansiblelint/schemas/tasks.json
---
- name: Join Docker Swarm as a worker
vars:
key: "{{ groups[managers_group] | map('extract', hostvars, ['swarm_info', 'swarm_facts', 'JoinTokens', 'Worker']) | list | first }}"
community.docker.docker_swarm:
state: join
join_token: "{{ key }}"
remote_addrs: "{{ groups[managers_group] | map('extract', hostvars, ['ansible_default_ipv4', 'address']) }}"