Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
root = true

[ansible/**]
charset = utf-8
end_of_line = lf
indent_size = 2
indent_style = space
insert_final_newline = false
max_line_length = 120
tab_width = 2
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_visual_guides = 80,120
ij_wrap_on_typing = false

[{*.mk,GNUmakefile,GNUmakefile.inc,makefile,makefile.inc}]
tab_width = 4
ij_visual_guides =
insert_final_newline = true

[{*.yaml,*.yml,*playbook.yaml,*playbook.yml,main.yaml,main.yml}]
insert_final_newline = true
ij_visual_guides =
ij_yaml_align_values_properties = do_not_align
ij_yaml_autoinsert_sequence_marker = true
ij_yaml_block_mapping_on_new_line = false
ij_yaml_indent_sequence_value = true
ij_yaml_keep_indents_on_empty_lines = false
ij_yaml_keep_line_breaks = true
ij_yaml_line_comment_add_space = false
ij_yaml_line_comment_add_space_on_reformat = false
ij_yaml_line_comment_at_first_column = true
ij_yaml_sequence_on_new_line = false
ij_yaml_space_before_colon = false
ij_yaml_spaces_within_braces = true
ij_yaml_spaces_within_brackets = true
20 changes: 20 additions & 0 deletions ansible/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
SSH_USER ?= root
HOST_ADDR ?= your.server.ip

PATH_TO_PRIVATE_KEY ?= path/to/private/key

lint:
ansible-lint ./roles

fix-lint:
ansible-lint ./roles --fix

playbook:
ansible-playbook \
-i ./inventory.ini \
./playbook.yml \
--user $(SSH_USER) \
--private-key $(PATH_TO_PRIVATE_KEY)

ssh:
ssh -o "ServerAliveInterval 10" -o "TCPKeepAlive yes" -i $(PATH_TO_PRIVATE_KEY) $(SSH_USER)@$(HOST_ADDR)
49 changes: 49 additions & 0 deletions ansible/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# cloud

```bash
ansible-galaxy collection install community.general # for ufw
```

### Handy commands

#### Lint the Ansible files

```bash
ansible-lint ./playbook.yml
```

#### Deploy the Ansible's playbook

```bash
ansible-playbook \
-i ./inventory.ini \
./playbook.yml \
--user root \
--private-key path/to/private/key
```

### Troubleshooting

#### Connect via SSH to the instance (and keep it running without freezing)

```bash
ssh -o "ServerAliveInterval 10" -o "TCPKeepAlive yes" -i path/to/private/key root@instance-address
```

#### Check the systemctl service status of the other's user

```bash
systemctl --user --machine=appuser@ status gladiator.service
```

#### Impersonate as other user and run bash (su for users without shell configured)

```bash
sudo machinectl shell appuser@ /bin/bash
```

#### Check the Quadlet configuration (convert container definition to a systemd service)

```bash
/usr/lib/systemd/system-generators/podman-system-generator --user --dryrun
```
6 changes: 6 additions & 0 deletions ansible/ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[defaults]
retry_files_enabled = False
result_format = yaml

[connection]
pipelining = True
5 changes: 5 additions & 0 deletions ansible/inventory.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[web]
your.server.ip ansible_user=your_ssh_user

;yourserver ansible_host={{ secrets.DEPLOY_HOST }}
;yourserver ansible_host=1.2.3.4 ansible_user=ubuntu
12 changes: 12 additions & 0 deletions ansible/playbook.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
- name: Deploy app
hosts: all
become: true
roles:
- podman
- security
- appuser
- gladiator
- nginx
# - prometheus
# - grafana
3 changes: 3 additions & 0 deletions ansible/requirements.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
collections:
- name: community.general
2 changes: 2 additions & 0 deletions ansible/roles/appuser/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
appuser_name: "appuser"
30 changes: 30 additions & 0 deletions ansible/roles/appuser/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
- name: Ensure appuser exists
"ansible.builtin.user":
name: "{{ appuser_name }}"
shell: /usr/sbin/nologin
create_home: true
home: "/home/{{ appuser_name }}"

- name: Get UID of appuser
ansible.builtin.command: "id -u {{ appuser_name }}"
register: appuser_uid_cmd
changed_when: false

- name: Export appuser UID
ansible.builtin.set_fact:
appuser_uid: "{{ appuser_uid_cmd.stdout }}"

# Rootless services require "lingering" to allow user systemd to start at boot.
- name: Ensure linger is enabled for appuser
ansible.builtin.command: "loginctl enable-linger {{ appuser_name }}"
args:
creates: "/var/lib/systemd/linger/{{ appuser_name }}"

- name: Set file limits for appuser
ansible.builtin.copy:
dest: /etc/security/limits.d/appuser.conf
content: |
appuser soft nofile 65535
appuser hard nofile 65535
mode: "0644"
18 changes: 18 additions & 0 deletions ansible/roles/gladiator/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
gladiator_container_name: gladiator
gladiator_image: ghcr.io/dimspell/gladiator:latest
gladiator_port: 2137

gladiator_env:
LOG_LEVEL: "debug"
LOG_FORMAT: "json"
CONSOLE_ADDR: "0.0.0.0:2137"
CONSOLE_PUBLIC_ADDR: "https://example.com"
RELAY_ADDR: "0.0.0.0:9999"
RELAY_PUBLIC_ADDR: "example:9999"
DATABASE_TYPE: "sqlite"
SQLITE_PATH: "/data/gladiator-db.sqlite"

gladiator_volume_container: /data

gladiator_env_file: "/etc/containers/systemd/{{ gladiator_container_name }}.env"
11 changes: 11 additions & 0 deletions ansible/roles/gladiator/handlers/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
- name: Restart gladiator
become: true
become_user: "{{ appuser_name }}"
ansible.builtin.systemd:
name: "{{ gladiator_container_name }}.service"
state: restarted
daemon_reload: true
scope: user
environment:
XDG_RUNTIME_DIR: "/run/user/{{ appuser_uid }}"
4 changes: 4 additions & 0 deletions ansible/roles/gladiator/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
dependencies:
- role: podman
- role: appuser
52 changes: 52 additions & 0 deletions ansible/roles/gladiator/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
- name: Ensure Podman and Quadlet dirs exist
ansible.builtin.file:
path: "{{ item }}"
state: directory
mode: "0755"
owner: "{{ appuser_name }}"
group: "{{ appuser_name }}"
loop:
- "/home/{{ appuser_name }}/.config/containers/systemd/"

- name: Deploy .env file
ansible.builtin.template:
src: gladiator.env.j2
dest: "{{ gladiator_env_file }}"
mode: "0644"
owner: "{{ appuser_name }}"
group: "{{ appuser_name }}"
notify: Restart gladiator

# Note: it will create the directory ~/.local/share/containers/storage/volumes/gladiator
- name: Deploy Quadlet volume unit
ansible.builtin.template:
src: gladiator.volume.j2
dest: "/home/{{ appuser_name }}/.config/containers/systemd/{{ gladiator_container_name }}.volume"
owner: "{{ appuser_name }}"
group: "{{ appuser_name }}"
mode: "0644"
notify: Restart gladiator

- name: Deploy Quadlet container unit
ansible.builtin.template:
src: gladiator.container.j2
dest: "/home/{{ appuser_name }}/.config/containers/systemd/{{ gladiator_container_name }}.container"
owner: "{{ appuser_name }}"
group: "{{ appuser_name }}"
mode: "0644"
notify: Restart gladiator

- name: Enable and start container service
become: true
become_method: ansible.builtin.su
become_user: "{{ appuser_name }}"
become_flags: "-s /bin/bash" # Specify a valid shell
ansible.builtin.systemd:
name: "{{ gladiator_container_name }}.service"
enabled: true
state: started
scope: user
daemon_reload: true
environment:
XDG_RUNTIME_DIR: "/run/user/{{ appuser_uid }}"
40 changes: 40 additions & 0 deletions ansible/roles/gladiator/templates/gladiator.container.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
[Unit]
Description=Gladiator Container

[Container]
Image={{ gladiator_image }}
AutoUpdate=registry
Label=io.containers.autoupdate=registry

ContainerName={{ gladiator_container_name }}

# Ports
PublishPort=127.0.0.1:2137:2137
PublishPort=0.0.0.0:9999:9999/udp

# Volumes
Volume=gladiator:{{ gladiator_volume_container }}

# Env file
EnvironmentFile={{ gladiator_env_file }}

# Logging
LogDriver=journald

# Health check
HealthCmd=curl -f http://localhost:2137/_health || exit 1
HealthInterval=30s
HealthRetries=3

User={{ appuser_uid }}
ReadOnly=true
DropCapability=ALL
NoNewPrivileges=true

Exec=console

[Service]
Restart=always

[Install]
WantedBy=default.target
3 changes: 3 additions & 0 deletions ansible/roles/gladiator/templates/gladiator.env.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{% for key, value in gladiator_env.items() %}
{{ key }}={{ value }}
{% endfor %}
4 changes: 4 additions & 0 deletions ansible/roles/gladiator/templates/gladiator.volume.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[Volume]
Type=bind
Source=/var/lib/gladiator
Options=rbind,rw
5 changes: 5 additions & 0 deletions ansible/roles/grafana/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
grafana_port: 3000
grafana_admin_user: admin
grafana_admin_password: admin
grafana_prometheus_url: "http://localhost:{{ prometheus_port }}"
45 changes: 45 additions & 0 deletions ansible/roles/grafana/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
- name: Add Grafana APT key
"ansible.builtin.apt_key":
url: https://packages.grafana.com/gpg.key
state: present

- name: Add Grafana APT repository
"ansible.builtin.apt_repository":
repo: "deb https://packages.grafana.com/oss/deb stable main"
state: present
filename: grafana

- name: Install Grafana
"ansible.builtin.apt":
name: grafana
update_cache: true
state: present

- name: Enable and start Grafana
ansible.builtin.systemd:
name: grafana-server
enabled: true
state: started

- name: Wait for Grafana to start
ansible.builtin.wait_for:
port: "{{ grafana_port }}"
timeout: 30

- name: Configure Prometheus data source
ansible.builtin.uri:
url: "http://localhost:{{ grafana_port }}/api/datasources"
method: POST
user: "{{ grafana_admin_user }}"
password: "{{ grafana_admin_password }}"
body_format: json
body:
name: "Prometheus"
type: "prometheus"
url: "{{ grafana_prometheus_url }}"
access: "proxy"
isDefault: true
status_code: 200,409 # 409 = already exists
headers:
Content-Type: "application/json"
5 changes: 5 additions & 0 deletions ansible/roles/nginx/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
nginx_domain_fqdn: "example.com"

nginx_site_name: "gladiator"
nginx_certbot_email: "user+letsencrypt@example.com"
Loading