diff --git a/lotus-land-story/caddy.yml b/lotus-land-story/caddy.yml new file mode 100644 index 0000000..1c9de52 --- /dev/null +++ b/lotus-land-story/caddy.yml @@ -0,0 +1,49 @@ +- name: Set up Caddy + hosts: lotus-land-story + vars_files: + - vars.yml + tasks: + + - name: Make /mnt/lotus-land-story/caddy + ansible.builtin.file: + path: /mnt/lotus-land-story/{{ item }} + state: directory + mode: "0755" + loop: + - caddy + - caddy/data + + - name: Set up Caddyfile + ansible.builtin.template: + src: templates/Caddyfile + dest: /mnt/lotus-land-story/caddy/Caddyfile + mode: "0644" + + - name: Run caddy + community.docker.docker_compose: + project_name: caddy + definition: + version: "3.3" + services: + caddy: + image: caddy:2 + container_name: caddy + ports: + - "80:80" + - "443:443" + - "2019:2019" + volumes: + - /mnt/lotus-land-story/caddy/Caddyfile:/etc/caddy/Caddyfile + - /mnt/lotus-land-story/caddy/data:/data + - caddy-config:/config + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + caddy-config: + + handlers: + - name: Import restarts + ansible.builtin.import_tasks: restarts.yml + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/docker.yml b/lotus-land-story/docker.yml new file mode 100644 index 0000000..4000841 --- /dev/null +++ b/lotus-land-story/docker.yml @@ -0,0 +1,78 @@ +# https://docs.docker.com/engine/install/debian/#install-using-the-repository +- name: Set up Docker + hosts: lotus-land-story + tasks: + + - name: Install Docker requirements + ansible.builtin.apt: + pkg: + - ca-certificates + - curl + - gnupg + state: present + + - name: Make /etc/apt/keyrings + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + + - name: Download Docker GPG key + ansible.builtin.shell: | + set -o pipefail + curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg + args: + creates: /etc/apt/keyrings/docker.gpg + + - name: Get architecture + ansible.builtin.command: dpkg --print-architecture + register: arch + changed_when: arch.rc != 0 + + - name: Set up Docker repository + ansible.builtin.template: + src: templates/docker.list + dest: /etc/apt/sources.list.d/docker.list + mode: "0644" + + - name: Install Docker + ansible.builtin.apt: + pkg: + - docker-ce + - docker-ce-cli + - containerd.io + - docker-buildx-plugin + - docker-compose-plugin + update_cache: true + + - name: Create Docker volume location + ansible.builtin.file: + path: /mnt/lotus-land-story/docker + state: directory + mode: "0755" + + - name: Get docker0 IP address + ansible.builtin.shell: ip -4 -o addr show docker0 | awk '{print $4}' # noqa: risky-shell-pipe + vars: + executable: /usr/bin/bash + register: docker_ip + changed_when: docker_ip.rc != 0 + + - name: Save docker_ip fact + ansible.builtin.set_fact: + docker_ip: + cidr: "{{ docker_ip.stdout }}" + address: "{{ docker_ip.stdout | ansible.utils.ipaddr('address') }}" + + - name: Configure Docker daemon + ansible.builtin.template: + src: templates/daemon.json + dest: /etc/docker/daemon.json + mode: "0644" + notify: Restart docker + + handlers: + - name: Import restarts + ansible.builtin.import_tasks: restarts.yml + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/grafana.yml b/lotus-land-story/grafana.yml new file mode 100644 index 0000000..2c6fc5d --- /dev/null +++ b/lotus-land-story/grafana.yml @@ -0,0 +1,62 @@ +- name: Set up Grafana + hosts: lotus-land-story + tasks: + + - name: Create Grafana dir + ansible.builtin.file: + path: /mnt/lotus-land-story/grafana/provisioning/{{ item }} + state: directory + mode: "0755" + loop: + - datasources + + - name: Configure grafana + ansible.builtin.copy: + dest: /mnt/lotus-land-story/grafana/grafana.ini + content: | + [metrics] + enabled = true + disable_total_stats = false + mode: "0644" + + - name: Provision Grafana + ansible.builtin.copy: + dest: /mnt/lotus-land-story/grafana/provisioning/datasources/prometheus.yml + content: | + apiVersion: 1 + + datasources: + - name: Prometheus + type: prometheus + # Access mode - proxy (server in the UI) or direct (browser in the UI). + access: proxy + url: http://host.docker.internal:9090 + jsonData: + httpMethod: POST + manageAlerts: true + prometheusType: Prometheus + prometheusVersion: 2.37.0 + mode: "0644" + + - name: Run Grafana + community.docker.docker_compose: + project_name: grafana + remove_orphans: true + definition: + version: "3.3" + services: + grafana: + image: grafana/grafana-oss:latest + ports: + - "3000:3000" + volumes: + - /mnt/lotus-land-story/grafana/grafana.ini:/etc/grafana/grafana.ini + - /mnt/lotus-land-story/grafana/provisioning:/etc/grafana/provisioning + - grafana:/var/lib/grafana + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + grafana: + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/main.yml b/lotus-land-story/main.yml index fd34eed..6050cfa 100644 --- a/lotus-land-story/main.yml +++ b/lotus-land-story/main.yml @@ -1,35 +1,13 @@ -- name: Set up lotus-land-story +- name: Base setup for lotus-land-story hosts: lotus-land-story vars_files: - vars.yml tasks: - - # https://wiki.debian.org/PostgreSql - - name: Install postgres - ansible.builtin.apt: - pkg: - - postgresql - - postgresql-client - state: present - - name: Always mount the lotus-land-story volume ansible.builtin.lineinfile: dest: /etc/fstab line: "{{ linode_volume }} /mnt/lotus-land-story ext4 defaults,noatime,nofail 0 2" state: present - - name: Make /mnt/lotus-land-story/postgresql - ansible.builtin.file: - path: /mnt/lotus-land-story/postgresql - state: directory - owner: postgres - mode: "0700" - - name: Set data directory to volume - ansible.builtin.lineinfile: - dest: "/etc/postgresql/13/main/postgresql.conf" - regexp: '^#?data_directory =' - line: "data_directory = '/mnt/lotus-land-story/postgresql'" - state: present - notify: Restart postgres - name: Install ansible requirements ansible.builtin.apt: @@ -40,347 +18,78 @@ - python3-psycopg2 state: present - # https://docs.docker.com/engine/install/debian/#install-using-the-repository - - name: Install docker - block: - - name: Install docker requirements - ansible.builtin.apt: - pkg: - - ca-certificates - - curl - - gnupg - state: present - - name: Make /etc/apt/keyrings - ansible.builtin.file: - path: /etc/apt/keyrings - state: directory - mode: "0755" - - name: Download Docker GPG key - ansible.builtin.shell: | - set -o pipefail - curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg - args: - creates: /etc/apt/keyrings/docker.gpg - - name: Get architecture - ansible.builtin.command: dpkg --print-architecture - register: arch - changed_when: arch.rc != 0 - - name: Set up docker repository - ansible.builtin.template: - src: templates/docker.list - dest: /etc/apt/sources.list.d/docker.list - mode: "0644" - - name: Install docker - ansible.builtin.apt: - pkg: - - docker-ce - - docker-ce-cli - - containerd.io - - docker-buildx-plugin - - docker-compose-plugin - update_cache: true - - name: Get docker0 IP address - ansible.builtin.shell: ip -4 -o addr show docker0 | awk '{print $4}' # noqa: risky-shell-pipe - vars: - executable: /usr/bin/bash - register: docker_ip - changed_when: docker_ip.rc != 0 - - name: Set docker ip fact - ansible.builtin.set_fact: - docker_ip: - cidr: "{{ docker_ip.stdout }}" - address: "{{ docker_ip.stdout | ansible.utils.ipaddr('address') }}" - - name: Create Docker volume location - ansible.builtin.file: - path: /mnt/lotus-land-story/docker - state: directory - mode: "0755" - - name: Docker config - ansible.builtin.template: - src: templates/daemon.json - dest: /etc/docker/daemon.json - mode: "0644" - notify: Restart docker - - - - name: Set up postgres - become: true - become_user: postgres - block: - - - name: Listen on docker0 interface - ansible.builtin.lineinfile: - dest: "/etc/postgresql/13/main/conf.d/listen.conf" - regexp: '^#?listen_addresses=' - line: "listen_addresses='localhost,{{ docker_ip.address }}'" - state: present - create: true - mode: "0644" - notify: Restart postgres - - - name: Set up postgres for miniflux - become: true - become_user: postgres - block: - - # https://miniflux.app/docs/installation.html#docker - - name: Create a miniflux db - community.postgresql.postgresql_db: - name: miniflux - notify: Restart postgres - - name: Create a miniflux db user - community.postgresql.postgresql_user: - db: miniflux - name: miniflux - password: "{{ miniflux_db_password }}" - notify: Restart postgres - - name: Grant miniflux access - community.postgresql.postgresql_pg_hba: - dest: /etc/postgresql/13/main/pg_hba.conf - contype: host - users: miniflux - source: samenet - databases: miniflux - create: true - notify: Restart postgres - - name: Install hstore - community.postgresql.postgresql_ext: - name: hstore - db: miniflux - notify: Restart postgres - - - name: Set up postgres-exporter - block: - - name: Get postgres roles - community.postgresql.postgresql_info: - filter: roles - register: postgres_info - - name: Add postgres permissions for postgres-exporter - community.postgresql.postgresql_query: - query: | - CREATE USER prometheus; - ALTER USER prometheus SET SEARCH_PATH TO prometheus,pg_catalog; - - CREATE SCHEMA prometheus AUTHORIZATION prometheus; - - CREATE FUNCTION prometheus.f_select_pg_stat_activity() - RETURNS setof pg_catalog.pg_stat_activity - LANGUAGE sql - SECURITY DEFINER - AS $$ - SELECT * from pg_catalog.pg_stat_activity; - $$; - - CREATE FUNCTION prometheus.f_select_pg_stat_replication() - RETURNS setof pg_catalog.pg_stat_replication - LANGUAGE sql - SECURITY DEFINER - AS $$ - SELECT * from pg_catalog.pg_stat_replication; - $$; - - CREATE VIEW prometheus.pg_stat_replication - AS - SELECT * FROM prometheus.f_select_pg_stat_replication(); - - CREATE VIEW prometheus.pg_stat_activity - AS - SELECT * FROM prometheus.f_select_pg_stat_activity(); - - GRANT SELECT ON prometheus.pg_stat_replication TO prometheus; - GRANT SELECT ON prometheus.pg_stat_activity TO prometheus; - when: "'prometheus' not in postgres_info.roles" +- import_playbook: postgres.yml # noqa: name[play] +- import_playbook: docker.yml # noqa: name[play] - - name: Run miniflux - community.docker.docker_compose: - project_name: miniflux - definition: - version: "3.3" - services: - miniflux: - image: miniflux/miniflux:latest - ports: - - "8080:8080" - environment: - - DATABASE_URL=postgres://miniflux:{{ miniflux_db_password }}@host.docker.internal/miniflux - - RUN_MIGRATIONS=1 - - CREATE_ADMIN=1 - - ADMIN_USERNAME=alpha - - ADMIN_PASSWORD={{ miniflux_password }} - - BASE_URL=https://rss.{{ domain }} - restart: unless-stopped - extra_hosts: - - "host.docker.internal:host-gateway" +- name: Set up postgres + hosts: lotus-land-story + tasks: - - name: Install host exporters - ansible.builtin.apt: - pkg: - - prometheus-node-exporter - - prometheus-postgres-exporter - state: present - # /usr/share/doc/prometheus-postgres-exporter/README.Debian - - name: Configure postgres-exporter + - name: Set up postgres to listen on docker0 interface ansible.builtin.lineinfile: - dest: /etc/default/prometheus-postgres-exporter - regexp: '^DATA_SOURCE_NAME=' - line: "DATA_SOURCE_NAME='user=prometheus host=/run/postgresql dbname=postgres'" + dest: "/etc/postgresql/13/main/conf.d/listen.conf" + regexp: '^#?listen_addresses=' + line: "listen_addresses='localhost,{{ docker_ip.address }}'" state: present - - name: Create Prometheus dir - ansible.builtin.file: - path: /mnt/lotus-land-story/prometheus - state: directory - mode: "0755" - - name: Prometheus config - ansible.builtin.copy: - dest: /mnt/lotus-land-story/prometheus/prometheus.yml - content: | - global: - # Attach these labels to any time series or alerts when communicating with - # external systems (federation, remote storage, Alertmanager). - external_labels: - monitor: 'codelab-monitor' - - scrape_configs: - - job_name: 'prometheus' - static_configs: - - targets: ['localhost:9090'] - - - job_name: node - static_configs: - - targets: ['host.docker.internal:9100'] - - - job_name: 'docker' - static_configs: - - targets: ['host.docker.internal:9323'] - - - job_name: caddy - static_configs: - - targets: ['host.docker.internal:2019'] - - - job_name: 'grafana' - static_configs: - - targets: ['host.docker.internal:3000'] - - - job_name: 'postgres' - static_configs: - - targets: ['host.docker.internal:9187'] - mode: "0644" - - name: Run Prometheus - community.docker.docker_compose: - project_name: prometheus - remove_orphans: true - definition: - version: "3.3" - services: - prometheus: - image: prom/prometheus:latest - ports: - - "9090:9090" - volumes: - - /mnt/lotus-land-story/prometheus:/etc/prometheus - restart: unless-stopped - extra_hosts: - - "host.docker.internal:host-gateway" - - - name: Create Grafana dir - ansible.builtin.file: - path: /mnt/lotus-land-story/grafana/provisioning/{{ item }} - state: directory - mode: "0755" - loop: - - datasources - - name: Configure grafana - ansible.builtin.copy: - dest: /mnt/lotus-land-story/grafana/grafana.ini - content: | - [metrics] - enabled = true - disable_total_stats = false + create: true mode: "0644" - - name: Provision Grafana - ansible.builtin.copy: - dest: /mnt/lotus-land-story/grafana/provisioning/datasources/prometheus.yml - content: | - apiVersion: 1 + notify: Restart postgres - datasources: - - name: Prometheus - type: prometheus - # Access mode - proxy (server in the UI) or direct (browser in the UI). - access: proxy - url: http://host.docker.internal:9090 - jsonData: - httpMethod: POST - manageAlerts: true - prometheusType: Prometheus - prometheusVersion: 2.37.0 - mode: "0644" - - name: Run Grafana - community.docker.docker_compose: - project_name: grafana - remove_orphans: true - definition: - version: "3.3" - services: - grafana: - image: grafana/grafana-oss:latest - ports: - - "3000:3000" - volumes: - - /mnt/lotus-land-story/grafana/grafana.ini:/etc/grafana/grafana.ini - - /mnt/lotus-land-story/grafana/provisioning:/etc/grafana/provisioning - - grafana:/var/lib/grafana - restart: unless-stopped - extra_hosts: - - "host.docker.internal:host-gateway" - volumes: - grafana: + handlers: + - name: Import restarts + ansible.builtin.import_tasks: restarts.yml - - name: Make /mnt/lotus-land-story/caddy - ansible.builtin.file: - path: /mnt/lotus-land-story/{{ item }} - state: directory - mode: "0755" - loop: - - caddy - - caddy/data - - name: Set up Caddyfile - ansible.builtin.template: - src: templates/Caddyfile - dest: /mnt/lotus-land-story/caddy/Caddyfile - mode: "0644" - - name: Run caddy - community.docker.docker_compose: - project_name: caddy - definition: - version: "3.3" - services: - caddy: - image: caddy:2 - container_name: caddy - ports: - - "80:80" - - "443:443" - - "2019:2019" - volumes: - - /mnt/lotus-land-story/caddy/Caddyfile:/etc/caddy/Caddyfile - - /mnt/lotus-land-story/caddy/data:/data - - caddy-config:/config - restart: unless-stopped - extra_hosts: - - "host.docker.internal:host-gateway" - volumes: - caddy-config: +- import_playbook: prometheus.yml # noqa: name[play] - handlers: - - name: Restart postgres - ansible.builtin.service: - name: postgresql - state: restarted +- name: Set up prometheus user in postgres + hosts: lotus-land-story + become: true + become_user: postgres + tasks: - - name: Restart docker - ansible.builtin.service: - name: docker - state: restarted + - name: Get postgres roles + community.postgresql.postgresql_info: + filter: roles + register: postgres_info + + - name: Add postgres permissions for postgres-exporter + community.postgresql.postgresql_query: + query: | + CREATE USER prometheus; + ALTER USER prometheus SET SEARCH_PATH TO prometheus,pg_catalog; + + CREATE SCHEMA prometheus AUTHORIZATION prometheus; + + CREATE FUNCTION prometheus.f_select_pg_stat_activity() + RETURNS setof pg_catalog.pg_stat_activity + LANGUAGE sql + SECURITY DEFINER + AS $$ + SELECT * from pg_catalog.pg_stat_activity; + $$; + + CREATE FUNCTION prometheus.f_select_pg_stat_replication() + RETURNS setof pg_catalog.pg_stat_replication + LANGUAGE sql + SECURITY DEFINER + AS $$ + SELECT * from pg_catalog.pg_stat_replication; + $$; + + CREATE VIEW prometheus.pg_stat_replication + AS + SELECT * FROM prometheus.f_select_pg_stat_replication(); + + CREATE VIEW prometheus.pg_stat_activity + AS + SELECT * FROM prometheus.f_select_pg_stat_activity(); + + GRANT SELECT ON prometheus.pg_stat_replication TO prometheus; + GRANT SELECT ON prometheus.pg_stat_activity TO prometheus; + when: "'prometheus' not in postgres_info.roles" + +- import_playbook: grafana.yml # noqa: name[play] +- import_playbook: miniflux.yml # noqa: name[play] +- import_playbook: caddy.yml # noqa: name[play] # vim: ft=yaml.ansible diff --git a/lotus-land-story/miniflux.yml b/lotus-land-story/miniflux.yml new file mode 100644 index 0000000..8413ec5 --- /dev/null +++ b/lotus-land-story/miniflux.yml @@ -0,0 +1,70 @@ +# https://miniflux.app/docs/installation.html#docker + +- name: Set up the Miniflux db + hosts: lotus-land-story + become: true + become_user: postgres + vars_files: + - vars.yml + tasks: + + - name: Create the Miniflux db + community.postgresql.postgresql_db: + name: miniflux + notify: Restart postgres + + - name: Create the Miniflux db user + community.postgresql.postgresql_user: + db: miniflux + name: miniflux + password: "{{ miniflux_db_password }}" + notify: Restart postgres + + - name: Grant Miniflux access to the db + community.postgresql.postgresql_pg_hba: + dest: /etc/postgresql/13/main/pg_hba.conf + contype: host + users: miniflux + source: samenet # TODO Can this be restricted to docker_ip? + databases: miniflux + create: true + notify: Restart postgres + + - name: Install hstore + community.postgresql.postgresql_ext: + name: hstore + db: miniflux + notify: Restart postgres + + handlers: + - name: Import restarts + ansible.builtin.import_tasks: restarts.yml + +- name: Set up the Miniflux db + hosts: lotus-land-story + vars_files: + - vars.yml + tasks: + + - name: Run miniflux + community.docker.docker_compose: + project_name: miniflux + definition: + version: "3.3" + services: + miniflux: + image: miniflux/miniflux:latest + ports: + - "8080:8080" + environment: + - DATABASE_URL=postgres://miniflux:{{ miniflux_db_password }}@host.docker.internal/miniflux + - RUN_MIGRATIONS=1 + - CREATE_ADMIN=1 + - ADMIN_USERNAME=alpha + - ADMIN_PASSWORD={{ miniflux_password }} + - BASE_URL=https://rss.{{ domain }} + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/postgres.yml b/lotus-land-story/postgres.yml new file mode 100644 index 0000000..c5b0f58 --- /dev/null +++ b/lotus-land-story/postgres.yml @@ -0,0 +1,32 @@ +# https://wiki.debian.org/PostgreSql +- name: Set up postgres + hosts: lotus-land-story + tasks: + + - name: Install postgres + ansible.builtin.apt: + pkg: + - postgresql + - postgresql-client + state: present + + - name: Make data directory + ansible.builtin.file: + path: /mnt/lotus-land-story/postgresql + state: directory + owner: postgres + mode: "0700" + + - name: Set data directory + ansible.builtin.lineinfile: + dest: "/etc/postgresql/13/main/postgresql.conf" + regexp: '^#?data_directory =' + line: "data_directory = '/mnt/lotus-land-story/postgresql'" + state: present + notify: Restart postgres + + handlers: + - name: Import restarts + ansible.builtin.import_tasks: restarts.yml + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/prometheus.yml b/lotus-land-story/prometheus.yml new file mode 100644 index 0000000..d6d5670 --- /dev/null +++ b/lotus-land-story/prometheus.yml @@ -0,0 +1,79 @@ +- name: Set up Prometheus + hosts: lotus-land-story + tasks: + + - name: Install host exporters + ansible.builtin.apt: + pkg: + - prometheus-node-exporter + - prometheus-postgres-exporter + state: present + + # /usr/share/doc/prometheus-postgres-exporter/README.Debian + - name: Configure postgres-exporter + ansible.builtin.lineinfile: + dest: /etc/default/prometheus-postgres-exporter + regexp: '^DATA_SOURCE_NAME=' + line: "DATA_SOURCE_NAME='user=prometheus host=/run/postgresql dbname=postgres'" + state: present + + - name: Create Prometheus dir + ansible.builtin.file: + path: /mnt/lotus-land-story/prometheus + state: directory + mode: "0755" + + - name: Prometheus config + ansible.builtin.copy: + dest: /mnt/lotus-land-story/prometheus/prometheus.yml + content: | + global: + # Attach these labels to any time series or alerts when communicating with + # external systems (federation, remote storage, Alertmanager). + external_labels: + monitor: 'codelab-monitor' + + scrape_configs: + - job_name: 'prometheus' + static_configs: + - targets: ['localhost:9090'] + + - job_name: node + static_configs: + - targets: ['host.docker.internal:9100'] + + - job_name: 'docker' + static_configs: + - targets: ['host.docker.internal:9323'] + + - job_name: caddy + static_configs: + - targets: ['host.docker.internal:2019'] + + - job_name: 'grafana' + static_configs: + - targets: ['host.docker.internal:3000'] + + - job_name: 'postgres' + static_configs: + - targets: ['host.docker.internal:9187'] + mode: "0644" + + - name: Run Prometheus + community.docker.docker_compose: + project_name: prometheus + remove_orphans: true + definition: + version: "3.3" + services: + prometheus: + image: prom/prometheus:latest + ports: + - "9090:9090" + volumes: + - /mnt/lotus-land-story/prometheus:/etc/prometheus + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + +# vim: ft=yaml.ansible diff --git a/lotus-land-story/restarts.yml b/lotus-land-story/restarts.yml new file mode 100644 index 0000000..27b44ff --- /dev/null +++ b/lotus-land-story/restarts.yml @@ -0,0 +1,11 @@ +- name: Restart postgres + ansible.builtin.service: + name: postgresql + state: restarted + +- name: Restart docker + ansible.builtin.service: + name: docker + state: restarted + +# vim: ft=yaml.ansible