5 Commits

16 changed files with 298 additions and 208 deletions

View File

@@ -9,7 +9,7 @@ Restart=always
[Container]
ContainerName=traefik
Image=docker.io/library/traefik:latest
Exec=--api.dashboard=true --api.insecure=true --certificatesresolvers.lets-encrypt.acme.email={{ infra_acme.email }} --certificatesresolvers.lets-encrypt.acme.storage=/{{ infra_acme.storage }} --certificatesresolvers.lets-encrypt.acme.tlschallenge=true --entrypoints.http --entrypoints.http.address=:80 --entrypoints.http.http.redirections.entryPoint.to=:443 --entrypoints.http.http.redirections.entryPoint.scheme=https --entrypoints.https --providers.docker=true
Exec=--api.dashboard=true --api.insecure=true --certificatesresolvers.lets-encrypt.acme.email={{ infra_acme.email }} --certificatesresolvers.lets-encrypt.acme.storage=/{{ infra_acme.storage }} --certificatesresolvers.lets-encrypt.acme.tlschallenge=true --entrypoints.http --entrypoints.http.address=:80 --entrypoints.http.http.redirections.entryPoint.to=:443 --entrypoints.http.http.redirections.entryPoint.scheme=https --entrypoints.https --providers.docker=true --providers.docker.network=podman
Network=podman
Notify=true
PublishPort=8080:8080

View File

@@ -0,0 +1,3 @@
[Network]
NetworkName=mastodon_external
Driver=bridge

View File

@@ -0,0 +1,3 @@
[Network]
NetworkName=mastodon_internal
Driver=bridge

View File

@@ -1,3 +1,8 @@
#SPDX-License-Identifier: MIT-0
---
# handlers file for mastodon
- name: Reload systemd user units
ansible.builtin.systemd_service:
daemon_reload: true
scope: user

View File

@@ -1,30 +1,13 @@
---
- name: Populate database variables
ansible.builtin.include_vars:
file: db.yml
- name: Render database quadlet
ansible.builtin.template:
src: database.container.j2
dest: "{{ mastodon_quadlet_tmp.path }}/database.container"
mode: "0644"
- name: Create DB instance for mastodon
containers.podman.podman_container:
name: database
image: docker.io/library/postgres:17
network:
- "{{ mastodon_networks['mastodon_internal']['name'] }}"
env:
POSTGRES_DB: mastodon
POSTGRES_USER: "{{ mastodon_database.username }}"
POSTGRES_PASSWORD: "{{ mastodon_database.password }}"
volumes:
- "/home/apps/mastodon/postgresql:/var/lib/postgresql/data:Z"
generate_systemd:
new: true
restart_policy: "always"
path: "~/.config/systemd/user/"
force: true
healthcheck: "pg_isready -U postgres"
- name: Activate database container service
ansible.builtin.systemd_service:
name: container-database.service
state: started
enabled: true
scope: user
- name: Install database quadlet
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/database.container"
reload_systemd: false
notify: Reload systemd user units

View File

@@ -1,31 +1,13 @@
---
- name: Create Elasticsearch instance for mastodon
containers.podman.podman_container:
name: elasticsearch
image: docker.elastic.co/elasticsearch/elasticsearch:7.17.29
network:
- "{{ mastodon_networks['mastodon_internal']['name'] }}"
- "{{ mastodon_networks['mastodon_external']['name'] }}"
volumes:
- "/home/apps/mastodon/elasticsearch:/usr/share/elasticsearch/data:Z"
env:
ES_JAVA_OPTS: "-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true"
xpack.license.self_generated.type: "basic"
xpack.security.enabled: "false"
xpack.watcher.enabled: "false"
xpack.graph.enabled: "false"
xpack.ml.enabled: "false"
bootstrap.memory_lock: "true"
cluster.name: "es-mastodon"
discovery.type: "single-node"
thread_pool.write.queue_size: "1000"
# generate_systemd:
# new: true
# restart_policy: "always"
# path: "~/.config/systemd/user/"
# force: true
restart_policy: "always"
healthcheck: "curl --silent --fail localhost:9200/_cluster/health || exit 1"
ulimit:
- "nofile=65536:65536"
- "memlock=-1:-1"
- name: Render elasticsearch quadlet
ansible.builtin.template:
src: elasticsearch.container.j2
dest: "{{ mastodon_quadlet_tmp.path }}/elasticsearch.container"
mode: "0644"
- name: Install elasticsearch quadlet
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/elasticsearch.container"
reload_systemd: false
notify: Reload systemd user units

View File

@@ -2,12 +2,11 @@
---
# tasks file for mastodon
- name: Setup mastodon networks
containers.podman.podman_network:
name: "{{ item['key'] }}"
driver: "{{ item['value']['driver'] }}"
disable_dns: "{{ item['value']['disable_dns'] }}"
loop: "{{ mastodon_networks | dict2items }}"
- name: Create quadlet staging directory
ansible.builtin.tempfile:
state: directory
prefix: mastodon-quadlets-
register: mastodon_quadlet_tmp
- name: Setup local directories
ansible.builtin.file:
@@ -15,6 +14,10 @@
state: directory
loop: "{{ mastodon_local_dirs }}"
- name: Populate database variables
ansible.builtin.include_vars:
file: db.yml
- name: Populate active record variables
ansible.builtin.include_vars:
file: web.yml
@@ -23,17 +26,80 @@
ansible.builtin.include_vars:
file: smtp.yml
- name: Create database container instance
- name: Stop legacy generated services
ansible.builtin.systemd_service:
name: "{{ item }}"
state: stopped
enabled: false
scope: user
failed_when: false
loop:
- container-database.service
- container-redis.service
- container-mastodon.service
- container-sidekiq.service
- name: Remove legacy generated service files
ansible.builtin.file:
path: "~/.config/systemd/user/{{ item }}"
state: absent
loop:
- container-database.service
- container-redis.service
- container-mastodon.service
- container-sidekiq.service
- name: Stage mastodon network quadlets
ansible.builtin.copy:
src: "{{ item }}"
dest: "{{ mastodon_quadlet_tmp.path }}/{{ item }}"
mode: "0644"
loop:
- mastodon_internal.network
- mastodon_external.network
- name: Install mastodon network quadlets
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/{{ item }}"
reload_systemd: false
loop:
- mastodon_internal.network
- mastodon_external.network
notify: Reload systemd user units
- name: Install database quadlet
ansible.builtin.include_tasks: db.yml
- name: Create redis container instance
- name: Install redis quadlet
ansible.builtin.include_tasks: redis.yml
- name: Create elasticsearch container instance
- name: Install elasticsearch quadlet
ansible.builtin.include_tasks: elasticsearch.yml
- name: Create web container instance
- name: Install web quadlet
ansible.builtin.include_tasks: web.yml
- name: Create sidekiq container instance
- name: Install sidekiq quadlet
ansible.builtin.include_tasks: sidekiq.yml
- name: Remove quadlet staging directory
ansible.builtin.file:
path: "{{ mastodon_quadlet_tmp.path }}"
state: absent
- name: Flush handlers so unit changes are reloaded before activation
ansible.builtin.meta: flush_handlers
- name: Activate mastodon services
ansible.builtin.systemd_service:
name: "{{ item }}"
state: started
enabled: true
scope: user
loop:
- database.service
- redis.service
- elasticsearch.service
- mastodon.service
- sidekiq.service

View File

@@ -1,22 +1,13 @@
---
- name: Create Redis instance for mastodon
containers.podman.podman_container:
name: redis
image: docker.io/library/redis:7
network:
- "{{ mastodon_networks['mastodon_internal']['name'] }}"
volumes:
- "/home/apps/mastodon/redis:/data:Z"
generate_systemd:
new: true
restart_policy: "always"
path: "~/.config/systemd/user/"
force: true
healthcheck: "redis-cli ping"
- name: Render redis quadlet
ansible.builtin.template:
src: redis.container.j2
dest: "{{ mastodon_quadlet_tmp.path }}/redis.container"
mode: "0644"
- name: Activate elasticsearch container service
ansible.builtin.systemd_service:
name: container-redis.service
state: started
enabled: true
scope: user
- name: Install redis quadlet
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/redis.container"
reload_systemd: false
notify: Reload systemd user units

View File

@@ -1,48 +1,13 @@
---
# TODO: it's not idempotent
- name: Create Sidekiq instance of mastodon
containers.podman.podman_container:
name: sidekiq
image: ghcr.io/mastodon/mastodon:v4.5.5
network:
- "{{ mastodon_networks['mastodon_internal']['name'] }}"
- "{{ mastodon_networks['mastodon_external']['name'] }}"
command: "bundle exec sidekiq"
env:
LOCAL_DOMAIN: "wtf.lt"
REDIS_HOST: redis
REDIS_PORT: 6379
DB_HOST: database
DB_NAME: mastodon
DB_USER: "{{ mastodon_database.username }}"
DB_PASS: "{{ mastodon_database.password }}"
DB_PORT: 5432
ES_ENABLED: true
ES_HOST: elasticsearch
ES_PORT: 9200
ES_PRESET: single_node_cluster
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: "{{ active_record_encryption.DETERMINISTIC_KEY }}"
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: "{{ active_record_encryption.KEY_DERIVATION_SALT }}"
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: "{{ active_record_encryption.PRIMARY_KEY }}"
SECRET_KEY_BASE: "{{ secret_key_base }}"
SMTP_SERVER: "{{ smtp.SERVER }}"
SMTP_PORT: "{{ smtp.PORT }}"
SMTP_LOGIN: "{{ smtp.LOGIN }}"
SMTP_PASSWORD: "{{ smtp.PASSWORD }}"
SMTP_FROM_ADDRESS: "{{ smtp.FROM_ADDRESS }}"
TRUSTED_PROXY_IP: "127.0.0.1/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7"
volumes:
- "/home/apps/mastodon/system:/mastodon/public/system:z"
generate_systemd:
new: true
restart_policy: "always"
path: "~/.config/systemd/user/"
force: true
healthcheck: "ps aux | grep '[s]idekiq 8' || false"
- name: Render sidekiq quadlet
ansible.builtin.template:
src: sidekiq.container.j2
dest: "{{ mastodon_quadlet_tmp.path }}/sidekiq.container"
mode: "0644"
- name: Activate sidekiq container service
ansible.builtin.systemd_service:
name: container-sidekiq.service
state: started
enabled: true
scope: user
- name: Install sidekiq quadlet
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/sidekiq.container"
reload_systemd: false
notify: Reload systemd user units

View File

@@ -1,64 +1,13 @@
---
- name: Populate active record variables
ansible.builtin.include_vars:
file: web.yml
- name: Render mastodon web quadlet
ansible.builtin.template:
src: mastodon.container.j2
dest: "{{ mastodon_quadlet_tmp.path }}/mastodon.container"
mode: "0644"
- name: Create Web instance of mastodon
containers.podman.podman_container:
name: mastodon
image: ghcr.io/mastodon/mastodon:v4.5.5
network:
- "{{ mastodon_networks['mastodon_internal']['name'] }}"
- "{{ mastodon_networks['mastodon_external']['name'] }}"
command: "bundle exec puma -C config/puma.rb"
env:
LOCAL_DOMAIN: "wtf.lt"
REDIS_HOST: redis
REDIS_PORT: 6379
DB_HOST: database
DB_NAME: mastodon
DB_USER: "{{ mastodon_database.username }}"
DB_PASS: "{{ mastodon_database.password }}"
DB_PORT: 5432
ES_ENABLED: true
ES_HOST: elasticsearch
ES_PORT: 9200
ES_PRESET: single_node_cluster
ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: "{{ active_record_encryption.DETERMINISTIC_KEY }}"
ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: "{{ active_record_encryption.KEY_DERIVATION_SALT }}"
ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: "{{ active_record_encryption.PRIMARY_KEY }}"
VAPID_PRIVATE_KEY: "{{ vapid.PRIVATE_KEY }}"
VAPID_PUBLIC_KEY: "{{ vapid.PUBLIC_KEY }}"
SECRET_KEY_BASE: "{{ secret_key_base }}"
SMTP_SERVER: "{{ smtp.SERVER }}"
SMTP_PORT: "{{ smtp.PORT }}"
SMTP_LOGIN: "{{ smtp.LOGIN }}"
SMTP_PASSWORD: "{{ smtp.PASSWORD }}"
SMTP_FROM_ADDRESS: "{{ smtp.FROM_ADDRESS }}"
# inspect traefik container and add the IP address here
TRUSTED_PROXY_IP: "127.0.0.1/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7"
label:
traefik.enable: "true"
traefik.http.routers.mastodon.rule: "Host(`wtf.lt`)"
traefik.http.middlewares.mastodon-https-redirect.redirectscheme.scheme: "https"
traefik.http.routers.mastodon.middlewares: "mastodon-https-redirect"
traefik.http.routers.mastodon-secure.entrypoints: "https"
traefik.http.routers.mastodon-secure.rule: "Host(`wtf.lt`)"
traefik.http.routers.mastodon-secure.tls: "true"
traefik.http.routers.mastodon-secure.tls.certresolver: "lets-encrypt"
traefik.http.services.mastodon.loadbalancer.server.port: "3000"
volumes:
- "/home/apps/mastodon/system:/mastodon/public/system:z"
generate_systemd:
new: true
restart_policy: "always"
path: "~/.config/systemd/user/"
force: true
healthcheck: "curl -s --noproxy localhost localhost:3000/health | grep -q OK"
- name: Activate mastodon web container service
ansible.builtin.systemd_service:
name: container-mastodon.service
state: started
enabled: true
scope: user
- name: Install mastodon web quadlet
containers.podman.podman_quadlet:
state: present
src: "{{ mastodon_quadlet_tmp.path }}/mastodon.container"
reload_systemd: false
notify: Reload systemd user units

View File

@@ -0,0 +1,18 @@
[Unit]
Description=Mastodon PostgreSQL database
[Container]
ContainerName=database
Image=docker.io/library/postgres:17
Network=mastodon_internal.network
Environment=POSTGRES_DB=mastodon
Environment=POSTGRES_USER={{ mastodon_database.username }}
Environment=POSTGRES_PASSWORD={{ mastodon_database.password }}
Volume=/home/apps/mastodon/postgresql:/var/lib/postgresql/data:Z
HealthCmd=pg_isready -U postgres
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,27 @@
[Unit]
Description=Mastodon Elasticsearch
[Container]
ContainerName=elasticsearch
Image=docker.elastic.co/elasticsearch/elasticsearch:7.17.29
Network=mastodon_internal.network
Environment=ES_JAVA_OPTS=-Xms512m -Xmx512m -Des.enforce.bootstrap.checks=true
Environment=xpack.license.self_generated.type=basic
Environment=xpack.security.enabled=false
Environment=xpack.watcher.enabled=false
Environment=xpack.graph.enabled=false
Environment=xpack.ml.enabled=false
Environment=bootstrap.memory_lock=true
Environment=cluster.name=es-mastodon
Environment=discovery.type=single-node
Environment=thread_pool.write.queue_size=1000
Volume=/home/apps/mastodon/elasticsearch:/usr/share/elasticsearch/data:Z
HealthCmd=curl --silent --fail localhost:9200/_cluster/health
Ulimit=nofile=65536:65536
Ulimit=memlock=-1:-1
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,53 @@
[Unit]
Description=Mastodon web
After=database.service redis.service elasticsearch.service
Requires=database.service redis.service elasticsearch.service
[Container]
ContainerName=mastodon
Image=ghcr.io/mastodon/mastodon:v4.6.4
Exec=bundle exec puma -C config/puma.rb
Network=mastodon_internal.network
Network=podman
Environment=LOCAL_DOMAIN=wtf.lt
Environment=REDIS_HOST=redis
Environment=REDIS_PORT=6379
Environment=DB_HOST=database
Environment=DB_NAME=mastodon
Environment=DB_USER={{ mastodon_database.username }}
Environment=DB_PASS={{ mastodon_database.password }}
Environment=DB_PORT=5432
Environment=ES_ENABLED=true
Environment=ES_HOST=elasticsearch
Environment=ES_PORT=9200
Environment=ES_PRESET=single_node_cluster
Environment=ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY={{ active_record_encryption.DETERMINISTIC_KEY }}
Environment=ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT={{ active_record_encryption.KEY_DERIVATION_SALT }}
Environment=ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY={{ active_record_encryption.PRIMARY_KEY }}
Environment=VAPID_PRIVATE_KEY={{ vapid.PRIVATE_KEY }}
Environment=VAPID_PUBLIC_KEY={{ vapid.PUBLIC_KEY }}
Environment=SECRET_KEY_BASE={{ secret_key_base }}
Environment=SMTP_SERVER={{ smtp.SERVER }}
Environment=SMTP_PORT={{ smtp.PORT }}
Environment=SMTP_LOGIN={{ smtp.LOGIN }}
Environment=SMTP_PASSWORD={{ smtp.PASSWORD }}
Environment=SMTP_FROM_ADDRESS={{ smtp.FROM_ADDRESS }}
Environment=TRUSTED_PROXY_IP=127.0.0.1/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7
Label=traefik.enable=true
Label=traefik.http.routers.mastodon.entrypoints=http
Label=traefik.http.routers.mastodon.rule=Host(`wtf.lt`)
Label=traefik.http.middlewares.mastodon-https-redirect.redirectscheme.scheme=https
Label=traefik.http.routers.mastodon.middlewares=mastodon-https-redirect
Label=traefik.http.routers.mastodon-secure.entrypoints=https
Label=traefik.http.routers.mastodon-secure.rule=Host(`wtf.lt`)
Label=traefik.http.routers.mastodon-secure.tls=true
Label=traefik.http.routers.mastodon-secure.tls.certresolver=lets-encrypt
Label=traefik.http.services.mastodon.loadbalancer.server.port=3000
Volume=/home/apps/mastodon/system:/mastodon/public/system:z
HealthCmd=/bin/sh -c "curl -s --noproxy localhost localhost:3000/health | grep -q OK"
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,15 @@
[Unit]
Description=Mastodon Redis
[Container]
ContainerName=redis
Image=docker.io/library/redis:7
Network=mastodon_internal.network
Volume=/home/apps/mastodon/redis:/data:Z
HealthCmd=redis-cli ping
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -0,0 +1,40 @@
[Unit]
Description=Mastodon Sidekiq
After=database.service redis.service elasticsearch.service
Requires=database.service redis.service elasticsearch.service
[Container]
ContainerName=sidekiq
Image=ghcr.io/mastodon/mastodon:v4.6.4
Exec=bundle exec sidekiq
Network=mastodon_internal.network
Environment=LOCAL_DOMAIN=wtf.lt
Environment=REDIS_HOST=redis
Environment=REDIS_PORT=6379
Environment=DB_HOST=database
Environment=DB_NAME=mastodon
Environment=DB_USER={{ mastodon_database.username }}
Environment=DB_PASS={{ mastodon_database.password }}
Environment=DB_PORT=5432
Environment=ES_ENABLED=true
Environment=ES_HOST=elasticsearch
Environment=ES_PORT=9200
Environment=ES_PRESET=single_node_cluster
Environment=ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY={{ active_record_encryption.DETERMINISTIC_KEY }}
Environment=ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT={{ active_record_encryption.KEY_DERIVATION_SALT }}
Environment=ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY={{ active_record_encryption.PRIMARY_KEY }}
Environment=SECRET_KEY_BASE={{ secret_key_base }}
Environment=SMTP_SERVER={{ smtp.SERVER }}
Environment=SMTP_PORT={{ smtp.PORT }}
Environment=SMTP_LOGIN={{ smtp.LOGIN }}
Environment=SMTP_PASSWORD={{ smtp.PASSWORD }}
Environment=SMTP_FROM_ADDRESS={{ smtp.FROM_ADDRESS }}
Environment=TRUSTED_PROXY_IP=127.0.0.1/8,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16,fc00::/7
Volume=/home/apps/mastodon/system:/mastodon/public/system:z
HealthCmd=/bin/sh -c "ps aux | grep '[s]idekiq 8'"
[Service]
Restart=always
[Install]
WantedBy=default.target

View File

@@ -2,16 +2,6 @@
---
# vars file for mastodon
mastodon_networks:
mastodon_internal:
name: mastodon_internal
driver: bridge
disable_dns: false
mastodon_external:
name: mastodon_external
driver: bridge
disable_dns: false
mastodon_local_dirs:
- "~/mastodon/postgresql"
- "~/mastodon/redis"