
By default gitea caches everything in memory using a Go hashmap. There is suspicion that the now many persistent AI web crawlers cause this hashmap to grow in ways that eventually cause the Go GC system to pause the world in noticeable ways when loading pages. Restarting the gitea services seems to temporarily reset things (as it should with an in memory map) until we cross some threshold and things become slow again. The good news is that gitea supports several backends (called adapters) for the cache. We elect to use memcached because it is relatively simple and has a FOSS license (unlike redis). The other alternative we could consider is twoqueue which also caches within memory in the Go runtime but allows for setting a size limit. I've gone with memcached because it doesn't rely on Golang GC, but twoqueue is likely simpler if we want to start there. Note we also bump the job timeout to 5400 seconds (90 minutes) from 4800 seconds (80 minutes) because a run on ovh-gra1 timed out while running testinfra test cases (the very end of the job). It is possible that using memcache is slightly slower than using in process memory caching, but the goal here isn't to make things faster it is to make things more consistent over time. As long as memcached performance is within the same ballpark and doesn't degrade over time this is acceptable. Change-Id: Ie9ca246a8321fe84d9a1582e35cd4c5459b48bee
266 lines
8.5 KiB
YAML
266 lines
8.5 KiB
YAML
- name: Ensure docker-compose directory exists
|
|
file:
|
|
state: directory
|
|
path: /etc/gitea-docker
|
|
mode: 0700
|
|
- name: Write docker-compose file
|
|
template:
|
|
src: docker-compose.yaml.j2
|
|
dest: /etc/gitea-docker/docker-compose.yaml
|
|
mode: 0600
|
|
- name: Ensure gitea volume directories exists
|
|
file:
|
|
state: directory
|
|
path: "/var/gitea/{{ item }}"
|
|
owner: 1000
|
|
group: 1000
|
|
loop:
|
|
- conf
|
|
- data
|
|
- logs
|
|
- certs
|
|
- db
|
|
- name: Write app.ini
|
|
template:
|
|
src: app.ini.j2
|
|
dest: /var/gitea/conf/app.ini
|
|
- name: Write mariadb conn limit config file
|
|
copy:
|
|
src: 99-max_conn_my.cnf
|
|
dest: /var/gitea/conf/99-max_conn_my.cnf
|
|
owner: root
|
|
group: root
|
|
mode: 0644
|
|
- name: Install distro packages
|
|
package:
|
|
name:
|
|
# TODO(clarkb) does the install-docker role handle these two packages?
|
|
- docker-compose
|
|
- python3-requests
|
|
# Installed to make checking memcached stats easy in testing and for
|
|
# human led debugging.
|
|
- netcat-openbsd
|
|
state: present
|
|
|
|
- name: Install reverse proxy
|
|
include_tasks: proxy.yaml
|
|
|
|
- name: Get list of image IDs pre pull
|
|
# The --quiet flag prints out only image IDs
|
|
command: docker image list --quiet
|
|
register: pre_pull_image_ids
|
|
|
|
- name: Run docker-compose pull
|
|
shell:
|
|
cmd: docker-compose pull
|
|
chdir: /etc/gitea-docker/
|
|
|
|
- name: Get list of image IDs post pull
|
|
# The --quiet flag prints out only image IDs
|
|
command: docker image list --quiet
|
|
register: post_pull_image_ids
|
|
|
|
- name: Stop/Start gitea safely for Gerrit replication
|
|
when: pre_pull_image_ids.stdout_lines|sort != post_pull_image_ids.stdout_lines|sort
|
|
block:
|
|
- name: Run docker-compose stop
|
|
shell:
|
|
cmd: docker-compose stop --timeout 60
|
|
chdir: /etc/gitea-docker/
|
|
- name: Run docker-compose up mariadb memcached gitea-web
|
|
shell:
|
|
cmd: docker-compose up -d --timeout 60 mariadb memcached gitea-web
|
|
chdir: /etc/gitea-docker/
|
|
|
|
# We wait here for the main gitea service to start before starting
|
|
# the ssh service. This is friendly to gerrit replication.
|
|
- name: Wait until the web service is sufficiently up to start ssh
|
|
uri:
|
|
url: "https://localhost:3000/api/v1/users/root"
|
|
validate_certs: false
|
|
status_code: 200, 404
|
|
register: root_user_check
|
|
delay: 1
|
|
retries: 300
|
|
until: root_user_check and root_user_check.status in (200, 404)
|
|
|
|
- name: Run docker-compose up gitea-ssh
|
|
shell:
|
|
cmd: docker-compose up -d --timeout 60 gitea-ssh
|
|
chdir: /etc/gitea-docker/
|
|
- name: Run docker prune to cleanup unneeded images
|
|
shell:
|
|
# Keep images around for 3 days before pruning them. Allows for
|
|
# easy rollback if necessary. Note "3d" seems to be rejected by
|
|
# docker but 72 hours == 3 days.
|
|
cmd: docker image prune -f --filter "until=72h"
|
|
|
|
# User management outside of service bringup to avoid confusion between
|
|
# the two stages.
|
|
- name: Check if root user exists
|
|
uri:
|
|
url: "https://localhost:3000/api/v1/users/root"
|
|
validate_certs: false
|
|
status_code: 200, 404
|
|
register: root_user_check
|
|
delay: 1
|
|
retries: 300
|
|
until: root_user_check and root_user_check.status in (200, 404)
|
|
- name: Create root user
|
|
when: root_user_check.status==404
|
|
block:
|
|
- name: Create root user
|
|
command: >
|
|
/usr/local/bin/docker-compose -f /etc/gitea-docker/docker-compose.yaml exec -T gitea-web
|
|
gitea admin user create --name root --password {{ gitea_root_password }} --email {{ gitea_root_email }} --admin
|
|
no_log: "{{ gitea_no_log }}"
|
|
- name: Check if gerrit user exists
|
|
uri:
|
|
url: "https://localhost:3000/api/v1/users/gerrit"
|
|
validate_certs: false
|
|
status_code: 200, 404
|
|
register: gerrit_user_check
|
|
- name: Create gerrit user
|
|
when: gerrit_user_check.status==404
|
|
no_log: true
|
|
uri:
|
|
url: "https://localhost:3000/api/v1/admin/users"
|
|
validate_certs: false
|
|
method: POST
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
status_code: 201
|
|
body_format: json
|
|
body:
|
|
email: "gerrit@review.opendev.org"
|
|
full_name: Gerrit
|
|
login_name: gerrit
|
|
must_change_password: false
|
|
password: "{{ gitea_gerrit_password }}"
|
|
send_notify: false
|
|
source_id: 0
|
|
username: gerrit
|
|
- name: List keys to determine which updates are necessary.
|
|
uri:
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
url: "https://localhost:3000/api/v1/users/gerrit/keys"
|
|
validate_certs: false
|
|
status_code: 200
|
|
register: gerrit_key_check
|
|
no_log: true
|
|
# We want to allow for multiple keys in order to do key rotations.
|
|
# Check if both keys are present. If a key is not present then add it
|
|
# to Gitea. Keep in mind the two keys may be the same in which case
|
|
# we can skip the second key creation. Finally clean up any keys
|
|
# that don't match the two keys. This allows us to do key rotations.
|
|
- name: Determine if key A and key B are already present
|
|
set_fact:
|
|
key_A_present: "{{ gerrit_key_check.json | selectattr('key', 'equalto', gitea_gerrit_public_key_A ) | list | length > 0 }}"
|
|
key_B_present: "{{ gerrit_key_check.json | selectattr('key', 'equalto', gitea_gerrit_public_key_B ) | list | length > 0 }}"
|
|
- name: Add gerrit ssh key A
|
|
when: not key_A_present
|
|
no_log: true
|
|
uri:
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
url: "https://localhost:3000/api/v1/admin/users/gerrit/keys"
|
|
validate_certs: false
|
|
method: POST
|
|
status_code: 201
|
|
body_format: json
|
|
body:
|
|
key: "{{ gitea_gerrit_public_key_A }}"
|
|
read_only: false
|
|
title: "Gerrit replication key A"
|
|
- name: Add gerrit ssh key B
|
|
when: not key_B_present and gitea_gerrit_public_key_A != gitea_gerrit_public_key_B
|
|
no_log: true
|
|
uri:
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
url: "https://localhost:3000/api/v1/admin/users/gerrit/keys"
|
|
validate_certs: false
|
|
method: POST
|
|
status_code: 201
|
|
body_format: json
|
|
body:
|
|
key: "{{ gitea_gerrit_public_key_B }}"
|
|
read_only: false
|
|
title: "Gerrit replication key B"
|
|
- name: List keys again to ensure key ids are correct for deletion.
|
|
uri:
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
url: "https://localhost:3000/api/v1/users/gerrit/keys"
|
|
validate_certs: false
|
|
status_code: 200
|
|
register: gerrit_key_check
|
|
no_log: true
|
|
- name: Delete old gerrit ssh keys
|
|
when: existing_pubkey.key != gitea_gerrit_public_key_A and existing_pubkey.key != gitea_gerrit_public_key_B
|
|
no_log: true
|
|
uri:
|
|
user: root
|
|
password: "{{ gitea_root_password }}"
|
|
force_basic_auth: true
|
|
url: "https://localhost:3000/api/v1/user/keys/{{ existing_pubkey.id }}"
|
|
validate_certs: false
|
|
method: DELETE
|
|
status_code: 204
|
|
loop: "{{ gerrit_key_check.json }}"
|
|
loop_control:
|
|
loop_var: existing_pubkey
|
|
- name: Set up cron job to pack git refs
|
|
cron:
|
|
name: pack-git-refs
|
|
state: present
|
|
job: >
|
|
/usr/local/bin/docker-compose -f /etc/gitea-docker/docker-compose.yaml exec -T gitea-web
|
|
find /data/git/repositories/ -maxdepth 2 -name *.git -type d -execdir git --git-dir={} gc --quiet \;
|
|
minute: '{{ 59 | random(seed=inventory_hostname) }}'
|
|
hour: '{{ 23 | random(seed=inventory_hostname) }}'
|
|
weekday: '*/2'
|
|
- name: Create db backup dest
|
|
file:
|
|
state: directory
|
|
path: /var/backups/gitea-mariadb
|
|
mode: 0700
|
|
owner: root
|
|
group: root
|
|
- name: Set up cron job to backup the database
|
|
cron:
|
|
name: gitea-db-backup
|
|
state: present
|
|
user: root
|
|
job: >
|
|
/usr/local/bin/docker-compose -f /etc/gitea-docker/docker-compose.yaml exec -T mariadb
|
|
bash -c '/usr/bin/mysqldump --opt --databases gitea --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"' |
|
|
gzip -9 > /var/backups/gitea-mariadb/gitea-mariadb.sql.gz
|
|
minute: 42
|
|
hour: 4
|
|
- name: Rotate db backups
|
|
include_role:
|
|
name: logrotate
|
|
vars:
|
|
logrotate_file_name: /var/backups/gitea-mariadb/gitea-mariadb.sql.gz
|
|
logrotate_compress: false
|
|
- name: Setup db backup streaming job
|
|
block:
|
|
- name: Create backup streaming config dir
|
|
file:
|
|
path: /etc/borg-streams
|
|
state: directory
|
|
|
|
- name: Create db streaming file
|
|
copy:
|
|
content: >-
|
|
/usr/local/bin/docker-compose -f /etc/gitea-docker/docker-compose.yaml exec -T mariadb
|
|
bash -c '/usr/bin/mysqldump --skip-extended-insert --databases gitea --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"'
|
|
dest: /etc/borg-streams/mysql
|