321 lines
9.5 KiB
YAML
321 lines
9.5 KiB
YAML
---
|
|
# Install Docker (required by Dokku)
|
|
- name: Install prerequisites
|
|
apt:
|
|
name:
|
|
- ca-certificates
|
|
- curl
|
|
- gnupg
|
|
- apt-transport-https
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Add Docker GPG key
|
|
ansible.builtin.get_url:
|
|
url: https://download.docker.com/linux/debian/gpg
|
|
dest: /usr/share/keyrings/docker-archive-keyring.asc
|
|
mode: '0644'
|
|
|
|
- name: Add Docker repository
|
|
ansible.builtin.deb822_repository:
|
|
name: docker
|
|
types: deb
|
|
uris: https://download.docker.com/linux/debian
|
|
suites: "{{ ansible_distribution_release }}"
|
|
components: stable
|
|
architectures: "{{ ansible_architecture | replace('x86_64', 'amd64') }}"
|
|
signed_by: /usr/share/keyrings/docker-archive-keyring.asc
|
|
state: present
|
|
|
|
- name: Install Docker packages
|
|
apt:
|
|
name:
|
|
- docker-ce
|
|
- docker-ce-cli
|
|
- containerd.io
|
|
- docker-compose-plugin
|
|
- docker-buildx-plugin
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Ensure Docker service is started and enabled
|
|
systemd:
|
|
name: docker
|
|
state: started
|
|
enabled: true
|
|
|
|
# Install Dokku
|
|
- name: Add Dokku GPG key
|
|
ansible.builtin.get_url:
|
|
url: https://packagecloud.io/dokku/dokku/gpgkey
|
|
dest: /usr/share/keyrings/dokku-archive-keyring.asc
|
|
mode: '0644'
|
|
|
|
- name: Add Dokku repository
|
|
ansible.builtin.deb822_repository:
|
|
name: dokku
|
|
types: deb
|
|
uris: https://packagecloud.io/dokku/dokku/debian
|
|
suites: "{{ dokku_apt_suite }}"
|
|
components: main
|
|
signed_by: /usr/share/keyrings/dokku-archive-keyring.asc
|
|
state: present
|
|
|
|
- name: Preseed Dokku configuration
|
|
ansible.builtin.debconf:
|
|
name: dokku
|
|
question: "{{ item.question }}"
|
|
value: "{{ item.value }}"
|
|
vtype: "{{ item.vtype }}"
|
|
loop:
|
|
- question: dokku/vhost_enable
|
|
value: "true"
|
|
vtype: boolean
|
|
- question: dokku/hostname
|
|
value: "{{ dokku_domain }}"
|
|
vtype: string
|
|
- question: dokku/skip_key_file
|
|
value: "true"
|
|
vtype: boolean
|
|
loop_control:
|
|
label: "{{ item.question }}"
|
|
|
|
- name: Install Dokku
|
|
apt:
|
|
name: dokku
|
|
state: present
|
|
update_cache: true
|
|
|
|
- name: Set Dokku global domain
|
|
command: dokku domains:set-global {{ dokku_domain }}
|
|
register: dokku_domain_result
|
|
changed_when: "'Set' in dokku_domain_result.stdout"
|
|
|
|
# SSH keys for git push access
|
|
- name: Fetch SSH keys
|
|
ansible.builtin.uri:
|
|
url: "{{ item.key }}"
|
|
return_content: true
|
|
register: ssh_key_responses
|
|
loop: "{{ dokku_ssh_keys }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
delegate_to: localhost
|
|
become: false
|
|
|
|
- name: Check existing Dokku SSH keys
|
|
command: dokku ssh-keys:list
|
|
register: dokku_existing_keys
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Add SSH keys to Dokku
|
|
shell: |
|
|
echo '{{ item.content.split("\n") | first }}' | dokku ssh-keys:add {{ item.item.name }}
|
|
when: "item.item.name not in dokku_existing_keys.stdout"
|
|
loop: "{{ ssh_key_responses.results }}"
|
|
loop_control:
|
|
label: "{{ item.item.name }}"
|
|
|
|
# Install dokku-postgres plugin
|
|
- name: Check if postgres plugin is installed
|
|
command: dokku plugin:list
|
|
register: dokku_plugins
|
|
changed_when: false
|
|
|
|
- name: Install dokku-postgres plugin
|
|
command: dokku plugin:install {{ dokku_postgres_plugin_url }}
|
|
when: "'postgres' not in dokku_plugins.stdout"
|
|
|
|
- name: Install dokku-redis plugin
|
|
command: dokku plugin:install {{ dokku_redis_plugin_url }}
|
|
when: "'redis' not in dokku_plugins.stdout"
|
|
|
|
# Create apps and postgres services
|
|
- name: Check existing apps
|
|
command: dokku apps:list
|
|
register: dokku_apps_list
|
|
changed_when: false
|
|
|
|
- name: Create Dokku apps
|
|
command: "dokku apps:create {{ item.name }}"
|
|
when: "item.name not in dokku_apps_list.stdout_lines"
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
|
|
- name: Set app domains
|
|
shell: |
|
|
current=$(dokku domains:report {{ item.name }} --domains-app-vhosts)
|
|
for domain in {{ item.domains | join(' ') }}; do
|
|
if ! echo "$current" | grep -q "$domain"; then
|
|
dokku domains:add {{ item.name }} "$domain"
|
|
fi
|
|
done
|
|
when: item.domains is defined
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: domains_result
|
|
changed_when: "'added' in domains_result.stdout | default('')"
|
|
|
|
- name: Check if app has SSL cert
|
|
shell: "dokku certs:report {{ item.name }} --ssl-enabled 2>&1"
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: certs_check
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Generate self-signed SSL cert for apps
|
|
shell: |
|
|
mkdir -p /home/dokku/{{ item.item.name }}/tls
|
|
openssl req -new -x509 -days 3650 -nodes \
|
|
-out /home/dokku/{{ item.item.name }}/tls/server.crt \
|
|
-keyout /home/dokku/{{ item.item.name }}/tls/server.key \
|
|
-subj "/CN={{ item.item.domains | first }}"
|
|
chown -R dokku:dokku /home/dokku/{{ item.item.name }}/tls
|
|
chmod 600 /home/dokku/{{ item.item.name }}/tls/server.key
|
|
dokku proxy:build-config {{ item.item.name }}
|
|
when:
|
|
- item.item.domains is defined
|
|
- "'true' not in item.stdout"
|
|
loop: "{{ certs_check.results }}"
|
|
loop_control:
|
|
label: "{{ item.item.name }}"
|
|
|
|
- name: Check existing postgres services
|
|
command: dokku postgres:list
|
|
register: dokku_postgres_list
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Create postgres services with TimescaleDB
|
|
command: >
|
|
dokku postgres:create {{ item.postgres.service_name }}
|
|
--image {{ dokku_postgres_image }}
|
|
--image-version {{ dokku_postgres_image_version }}
|
|
when:
|
|
- item.postgres is defined
|
|
- "item.postgres.service_name not in dokku_postgres_list.stdout"
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: postgres_create_result
|
|
|
|
# Handle TimescaleDB SSL cert issue - container may get stuck restarting without certs
|
|
- name: Wait for postgres services to stabilize
|
|
pause:
|
|
seconds: 10
|
|
when: postgres_create_result.changed | default(false)
|
|
|
|
- name: Check postgres service status
|
|
command: "dokku postgres:info {{ item.postgres.service_name }}"
|
|
when:
|
|
- item.postgres is defined
|
|
- postgres_create_result.changed | default(false)
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: postgres_info
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Fix TimescaleDB SSL certs if container is restarting
|
|
shell: |
|
|
CONTAINER_ID=$(docker ps -a --filter "name=dokku.postgres.{{ item.postgres.service_name }}" --format '{{"{{"}}.ID{{"}}"}}')
|
|
if [ -n "$CONTAINER_ID" ]; then
|
|
DATA_DIR=$(docker inspect "$CONTAINER_ID" --format '{{"{{" }}range .Mounts{{"}}"}}{{"{{"}}if eq .Destination "/var/lib/postgresql/data"{{"}}"}}{{"{{"}} .Source {{"}}"}}{{"{{"}}end{{"}}"}}{{"{{"}}end{{"}}"}}')
|
|
if [ -n "$DATA_DIR" ] && [ ! -f "$DATA_DIR/server.crt" ]; then
|
|
openssl req -new -x509 -days 3650 -nodes \
|
|
-out "$DATA_DIR/server.crt" \
|
|
-keyout "$DATA_DIR/server.key" \
|
|
-subj "/CN=dokku-postgres-{{ item.postgres.service_name }}"
|
|
chown 999:999 "$DATA_DIR/server.crt" "$DATA_DIR/server.key"
|
|
chmod 600 "$DATA_DIR/server.key"
|
|
dokku postgres:restart {{ item.postgres.service_name }}
|
|
fi
|
|
fi
|
|
when:
|
|
- item.postgres is defined
|
|
- postgres_create_result.changed | default(false)
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
changed_when: false
|
|
|
|
# Enable TimescaleDB extension
|
|
- name: Enable timescaledb extension
|
|
shell: |
|
|
echo "CREATE EXTENSION IF NOT EXISTS timescaledb;" | dokku postgres:connect {{ item.postgres.service_name }}
|
|
when:
|
|
- item.postgres is defined
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: timescaledb_ext
|
|
changed_when: "'CREATE EXTENSION' in timescaledb_ext.stdout"
|
|
failed_when:
|
|
- timescaledb_ext.rc != 0
|
|
- "'already exists' not in timescaledb_ext.stderr"
|
|
|
|
# Link postgres to apps
|
|
- name: Check postgres links
|
|
shell: "dokku postgres:linked {{ item.postgres.service_name }} {{ item.name }} && echo linked || echo not_linked"
|
|
when:
|
|
- item.postgres is defined
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: postgres_link_check
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Link postgres to apps
|
|
command: "dokku postgres:link {{ item.item.postgres.service_name }} {{ item.item.name }}"
|
|
when:
|
|
- item.item.postgres is defined
|
|
- "'not_linked' in item.stdout"
|
|
loop: "{{ postgres_link_check.results }}"
|
|
loop_control:
|
|
label: "{{ item.item.name }}"
|
|
|
|
# Redis/Valkey services
|
|
- name: Check existing redis services
|
|
command: dokku redis:list
|
|
register: dokku_redis_list
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Create redis services with Valkey
|
|
command: >
|
|
dokku redis:create {{ item.redis.service_name }}
|
|
--image {{ dokku_redis_image }}
|
|
--image-version {{ dokku_redis_image_version }}
|
|
when:
|
|
- item.redis is defined
|
|
- "item.redis.service_name not in dokku_redis_list.stdout"
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
|
|
- name: Check redis links
|
|
shell: "dokku redis:linked {{ item.redis.service_name }} {{ item.name }} && echo linked || echo not_linked"
|
|
when:
|
|
- item.redis is defined
|
|
loop: "{{ dokku_apps }}"
|
|
loop_control:
|
|
label: "{{ item.name }}"
|
|
register: redis_link_check
|
|
changed_when: false
|
|
failed_when: false
|
|
|
|
- name: Link redis to apps
|
|
command: "dokku redis:link {{ item.item.redis.service_name }} {{ item.item.name }}"
|
|
when:
|
|
- item.item.redis is defined
|
|
- "'not_linked' in item.stdout"
|
|
loop: "{{ redis_link_check.results }}"
|
|
loop_control:
|
|
label: "{{ item.item.name }}"
|