prepare for ipv6 deployment

This commit is contained in:
Iurii Tatishchev 2023-04-03 03:47:01 -07:00
parent 20ce67472d
commit 40de9b87a1
Signed by: CaZzzer
GPG Key ID: 9A156B7DA6398968
16 changed files with 177 additions and 24 deletions

1
.idea/alpina.iml generated
View File

@ -28,6 +28,7 @@
<option value="$MODULE_DIR$/roles/nextcloud/templates" /> <option value="$MODULE_DIR$/roles/nextcloud/templates" />
<option value="$MODULE_DIR$/roles/arrstack/templates" /> <option value="$MODULE_DIR$/roles/arrstack/templates" />
<option value="$MODULE_DIR$/roles/jellyfin/templates" /> <option value="$MODULE_DIR$/roles/jellyfin/templates" />
<option value="$MODULE_DIR$/roles/docker_host/templates" />
</list> </list>
</option> </option>
</component> </component>

23
.idea/jsonSchemas.xml generated
View File

@ -3,6 +3,24 @@
<component name="JsonSchemaMappingsProjectConfiguration"> <component name="JsonSchemaMappingsProjectConfiguration">
<state> <state>
<map> <map>
<entry key="Ansible Tasks File">
<value>
<SchemaInfo>
<option name="name" value="Ansible Tasks File" />
<option name="relativePathToSchema" value="https://raw.githubusercontent.com/ansible/ansible-lint/main/src/ansiblelint/schemas/ansible.json#/$defs/tasks" />
<option name="applicationDefined" value="true" />
<option name="patterns">
<list>
<Item>
<option name="pattern" value="true" />
<option name="path" value="*/tasks/*.yml" />
<option name="mappingKind" value="Pattern" />
</Item>
</list>
</option>
</SchemaInfo>
</value>
</entry>
<entry key="Traefik v2"> <entry key="Traefik v2">
<value> <value>
<SchemaInfo> <SchemaInfo>
@ -45,6 +63,11 @@
<option name="applicationDefined" value="true" /> <option name="applicationDefined" value="true" />
<option name="patterns"> <option name="patterns">
<list> <list>
<Item>
<option name="pattern" value="true" />
<option name="path" value="*/docker-compose.yml" />
<option name="mappingKind" value="Pattern" />
</Item>
<Item> <Item>
<option name="pattern" value="true" /> <option name="pattern" value="true" />
<option name="path" value="*/docker-compose.yml.j2" /> <option name="path" value="*/docker-compose.yml.j2" />

View File

@ -1,4 +1,6 @@
.POSIX: .POSIX:
.PHONY: *
.EXPORT_ALL_VARIABLES:
env ?= staging env ?= staging
vault_id ?= alpina@contrib/rbw-client.sh vault_id ?= alpina@contrib/rbw-client.sh

View File

@ -2,3 +2,17 @@
A home for configuring all of my homelab containers on a Debian Linux machine. A home for configuring all of my homelab containers on a Debian Linux machine.
This assumes a Debian Linux machine with Docker and Docker Compose installed. This assumes a Debian Linux machine with Docker and Docker Compose installed.
# Notes
## IPv6
The current configuration is designed to work with IPv6.
However, because of how (not properly) I'm doing the subnetting
from the host's network, NDP doesn't work.
This means that container IPs are not accessible from other hosts on the local network.
I simply have a static route on my router to the container subnet,
that uses the IP of this host as the gateway.
This is a limitation of my current ISP, I only have a single /64 subnet for my lab network.
I'd like to get a /56 or /48, perhaps using Hurricane Electric's tunnel broker.
*Sigh* ISPs being stingy with the 2^48 prefixes they're afraid of running out of.

View File

@ -1,3 +1,11 @@
{% macro default_network(subnet_index) %}
default:
enable_ipv6: true
ipam:
config:
- subnet: {{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, subnet_index) }}
{% endmacro %}
{% macro traefik_labels(host, service="", port="", auth=false) %} {% macro traefik_labels(host, service="", port="", auth=false) %}
traefik.enable=true traefik.enable=true
- traefik.http.routers.{{ host }}.rule=Host(`{{ host }}.{{ domain }}`) - traefik.http.routers.{{ host }}.rule=Host(`{{ host }}.{{ domain }}`)

View File

@ -28,8 +28,12 @@
when: item.state == "file" when: item.state == "file"
- name: Deploy docker-compose for {{ current_svc_name }} - name: Deploy docker-compose for {{ current_svc_name }}
community.docker.docker_compose: command: docker compose -f "{{ current_svc_path }}/docker-compose.yml" up -d --pull --remove-orphans
project_src: "{{ current_svc_path }}" register: docker_compose_output
state: present # Not perfect idempotency, but the built-in docker_compose module doesn't support docker-compose v2
pull: true # And of course there's an IPv6 bug in docker-compose v1, smh
remove_orphans: true # https://github.com/docker/compose/issues/7670
changed_when: "'created' in docker_compose_output.stderr.lower()"
- debug:
var: docker_compose_output

View File

@ -0,0 +1 @@
docker_ipv6_index: 255

View File

@ -0,0 +1 @@
docker_ipv6_index: 254

14
poetry.lock generated
View File

@ -254,6 +254,18 @@ files = [
{file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"},
] ]
[[package]]
name = "netaddr"
version = "0.8.0"
description = "A network address manipulation library for Python"
category = "main"
optional = false
python-versions = "*"
files = [
{file = "netaddr-0.8.0-py2.py3-none-any.whl", hash = "sha256:9666d0232c32d2656e5e5f8d735f58fd6c7457ce52fc21c98d45f2af78f990ac"},
{file = "netaddr-0.8.0.tar.gz", hash = "sha256:d6cc57c7a07b1d9d2e917aa8b36ae8ce61c35ba3fcd1b83ca31c5a0ee2b5a243"},
]
[[package]] [[package]]
name = "packaging" name = "packaging"
version = "23.0" version = "23.0"
@ -366,4 +378,4 @@ testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (
[metadata] [metadata]
lock-version = "2.0" lock-version = "2.0"
python-versions = "^3.10" python-versions = "^3.10"
content-hash = "4c3656f66006d184debf3777b8df073898df0eb1f53611cdd47ec4c543071595" content-hash = "e5cad99dc808b0751037fa8d524f2a4c4eac8f6ae5710c6ed5f32def518746b9"

View File

@ -9,6 +9,7 @@ readme = "README.md"
python = "^3.10" python = "^3.10"
ansible = "^7.3.0" ansible = "^7.3.0"
ansible-vault = "^2.1.0" ansible-vault = "^2.1.0"
netaddr = "^0.8.0"
[build-system] [build-system]

View File

@ -1,3 +1,12 @@
- name: Install Debian packages
become: yes
ansible.builtin.apt:
name:
- docker-ce
- docker-compose-plugin
- ufw
state: latest
- name: Upgrade Debian packages - name: Upgrade Debian packages
become: yes become: yes
ansible.builtin.apt: ansible.builtin.apt:
@ -8,6 +17,26 @@
state: latest state: latest
register: apt_upgrades register: apt_upgrades
- name: Allow SSH
become: yes
ufw:
rule: allow
name: OpenSSH
- name: Allow Web
become: yes
ufw:
rule: allow
name: WWW Full
- name: Enable Firewall
become: yes
ufw:
state: enabled
policy: reject
direction: incoming
logging: on
- name: Reboot if needed - name: Reboot if needed
become: yes become: yes
ansible.builtin.reboot: ansible.builtin.reboot:

View File

@ -3,3 +3,31 @@
state: directory state: directory
path: "{{ my_svc_path }}" path: "{{ my_svc_path }}"
mode: "700" mode: "700"
- name: Get IPv6 subnet for Docker
set_fact:
docker_ipv6_subnet: "{{ \
ansible_default_ipv6.address \
| ansible.utils.ipsubnet(64) \
| ansible.utils.ipsubnet(72, docker_ipv6_index) \
}}"
- debug:
var: docker_ipv6_subnet
- name: Configure Docker daemon
become: yes
template:
src: "daemon.json.j2"
dest: "/etc/docker/daemon.json"
owner: root
group: root
mode: "0644"
register: docker_daemon_config
- name: Restart Docker daemon
become: yes
service:
name: docker
state: restarted
when: docker_daemon_config.changed

View File

@ -0,0 +1,4 @@
{
"ipv6": true,
"fixed-cidr-v6": "{{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, 0) }}"
}

View File

@ -1,35 +1,37 @@
{% from "contrib/compose_helpers.j2" import traefik_labels with context %} {% import 'contrib/compose_helpers.j2' as helpers with context %}
{##} {##}
version: "3.7" version: "3.9"
networks: networks:
default:
traefik: traefik:
internal: true internal: true
enable_ipv6: true
ipam: ipam:
config: config:
- subnet: {{ traefik_ip }}/24 - subnet: {{ traefik_ip }}/24
- subnet: {{ docker_ipv6_subnet | ansible.utils.ipsubnet(80, 255) }}
services: services:
traefik: traefik:
image: traefik:v2.9 image: traefik:v2.9
container_name: traefik container_name: traefik
labels:
- {{ traefik_labels("traefik", service="api@internal") | indent(6) }}
restart: unless-stopped restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "8080:8080"
env_file: env_file:
- .env.traefik - .env.traefik
networks: network_mode: host
default:
traefik:
ipv4_address: {{ traefik_ip }}
volumes: volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./traefik.yml:/etc/traefik/traefik.yml:ro - ./traefik.yml:/etc/traefik/traefik.yml:ro
- {{ base_volume_path }}/traefik/rules:/rules:ro - ./rules:/rules:ro
- /var/run/docker.sock:/var/run/docker.sock:ro
- {{ base_volume_path }}/traefik/rules:/rules/extra:ro
- {{ base_volume_path }}/traefik/logs:/logs - {{ base_volume_path }}/traefik/logs:/logs
- {{ base_volume_path }}/traefik/acme:/acme - {{ base_volume_path }}/traefik/acme:/acme
# This is mostly just so that the traefik network gets created
whoami:
image: containous/whoami
container_name: whoami
labels:
- {{ helpers.traefik_labels('whoami', port=80) | indent(6) }}
networks:
- traefik

View File

@ -0,0 +1,25 @@
http:
routers:
traefik-dash:
rule: "Host(`traefik.{{ domain }}`)"
entryPoints:
- web
service: traefik-dash
traefik-dash-tls:
rule: "Host(`traefik.{{ domain }}`)"
entryPoints:
- websecure
service: traefik-dash
tls:
certResolver: letsencrypt
domains:
- main: "{{ domain }}"
sans:
- "*.{{ domain }}"
services:
traefik-dash:
loadBalancer:
servers:
- url: "http://localhost:8080"

View File

@ -11,9 +11,7 @@ accessLog:
entryPoints: entryPoints:
web: web:
address: ":80" address: ":80"
forwardedHeaders:
trustedIPs:
- "172.16.0.0/12"
websecure: websecure:
address: ":443" address: ":443"