diff --git a/lotus-land-story/Rakefile b/lotus-land-story/Rakefile index da4c765..27c9d49 100644 --- a/lotus-land-story/Rakefile +++ b/lotus-land-story/Rakefile @@ -10,6 +10,7 @@ namespace :pip do sh "pip-sync requirements.txt" end + desc "" task :upgrade do out, _ = Open3.capture2e("pip-compile --upgrade --resolver=backtracking requirements.in") File.write("requirements.txt", out) @@ -21,10 +22,12 @@ namespace :pip do end end +desc "" task terraform: "terraform.tfvars" do sh "terraform apply" end +desc "" task ansible: "vars.yml" do sh "ansible-playbook main.yml" end diff --git a/lotus-land-story/main.tf b/lotus-land-story/main.tf index 1cab02c..cfc9bd7 100644 --- a/lotus-land-story/main.tf +++ b/lotus-land-story/main.tf @@ -52,13 +52,21 @@ data "linode_domain" "domain" { domain = var.domain } -resource "linode_domain_record" "rww" { - domain_id = data.linode_domain.domain.id - name = "rss" - record_type = "A" - target = resource.linode_instance.lotus_land_story.ip_address +resource "linode_domain_record" "subdomains" { + domain_id = data.linode_domain.domain.id + record_type = "A" + target = resource.linode_instance.lotus_land_story.ip_address + + for_each = toset(["rss", "prometheus", "grafana"]) + name = each.key } +resource "linode_domain_record" "prometheus" { + domain_id = data.linode_domain.domain.id + name = "prometheus" + record_type = "A" + target = resource.linode_instance.lotus_land_story.ip_address +} output "lotus_land_story_ip" { value = resource.linode_instance.lotus_land_story.ip_address diff --git a/lotus-land-story/main.yml b/lotus-land-story/main.yml index 1b51e11..fd34eed 100644 --- a/lotus-land-story/main.yml +++ b/lotus-land-story/main.yml @@ -79,23 +79,40 @@ - docker-buildx-plugin - docker-compose-plugin update_cache: true - - - name: Set up postgres - become: true - become_user: postgres - block: - - 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.stdout | ansible.utils.ipaddr('address') }}'" + line: "listen_addresses='localhost,{{ docker_ip.address }}'" state: present create: true mode: "0644" @@ -132,6 +149,48 @@ 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" + - name: Run miniflux community.docker.docker_compose: project_name: miniflux @@ -149,8 +208,133 @@ - ADMIN_USERNAME=alpha - ADMIN_PASSWORD={{ miniflux_password }} - BASE_URL=https://rss.{{ domain }} + restart: unless-stopped + extra_hosts: + - "host.docker.internal:host-gateway" + + - 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" + + - 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: - name: Make /mnt/lotus-land-story/caddy ansible.builtin.file: @@ -160,7 +344,6 @@ loop: - caddy - caddy/data - - caddy/config - name: Set up Caddyfile ansible.builtin.template: src: templates/Caddyfile @@ -178,12 +361,16 @@ ports: - "80:80" - "443:443" + - "2019:2019" volumes: - /mnt/lotus-land-story/caddy/Caddyfile:/etc/caddy/Caddyfile - /mnt/lotus-land-story/caddy/data:/data - - /mnt/lotus-land-story/caddy/config:/config + - caddy-config:/config + restart: unless-stopped extra_hosts: - "host.docker.internal:host-gateway" + volumes: + caddy-config: handlers: - name: Restart postgres @@ -191,4 +378,9 @@ name: postgresql state: restarted + - name: Restart docker + ansible.builtin.service: + name: docker + state: restarted + # vim: ft=yaml.ansible diff --git a/lotus-land-story/templates/Caddyfile b/lotus-land-story/templates/Caddyfile index f36e473..4bd1534 100644 --- a/lotus-land-story/templates/Caddyfile +++ b/lotus-land-story/templates/Caddyfile @@ -1,2 +1,15 @@ -rss.{{ domain }} -reverse_proxy host.docker.internal:8080 +:2019 { + metrics +} + +rss.{{ domain }} { + reverse_proxy host.docker.internal:8080 +} + +prometheus.{{ domain }} { + reverse_proxy host.docker.internal:9090 +} + +grafana.{{ domain }} { + reverse_proxy host.docker.internal:3000 +} diff --git a/lotus-land-story/templates/daemon.json b/lotus-land-story/templates/daemon.json new file mode 100644 index 0000000..ba28dd9 --- /dev/null +++ b/lotus-land-story/templates/daemon.json @@ -0,0 +1,4 @@ +{ + "data-root": "/mnt/lotus-land-story/docker", + "metrics-addr": "{{ docker_ip.address }}:9323" +}