test: CI/CD pipeline staging test - Redis aktiviert, Bad Gateway dokumentiert

This commit is contained in:
2025-11-07 20:54:44 +01:00
parent c088d08639
commit e8a26d7807
8 changed files with 276 additions and 96 deletions

View File

@@ -320,3 +320,4 @@ make setup
# Deployment (Code + Compose auf Server bringen) # Deployment (Code + Compose auf Server bringen)
make deploy make deploy
# CI/CD Pipeline Test - Fri Nov 7 08:54:41 PM CET 2025

View File

@@ -47,6 +47,7 @@
- **`setup-gitea-runner-ci.yml`** - Gitea Runner CI Setup - **`setup-gitea-runner-ci.yml`** - Gitea Runner CI Setup
- **`setup-gitea-initial-config.yml`** - Gitea Initial Setup (automatisiert via app.ini + CLI) - **`setup-gitea-initial-config.yml`** - Gitea Initial Setup (automatisiert via app.ini + CLI)
- **`setup-gitea-repository.yml`** - Erstellt Repository in Gitea und konfiguriert Git-Remote (automatisiert via API) - **`setup-gitea-repository.yml`** - Erstellt Repository in Gitea und konfiguriert Git-Remote (automatisiert via API)
- **`update-gitea-config.yml`** - Aktualisiert Gitea-Konfiguration (Cache, Connection Pooling) zur Behebung von Performance-Problemen
- **`install-docker.yml`** - Docker Installation auf Server - **`install-docker.yml`** - Docker Installation auf Server
## Entfernte/Legacy Playbooks ## Entfernte/Legacy Playbooks

View File

@@ -1,49 +1,134 @@
--- ---
- name: Update Gitea Configuration and Restart # Ansible Playbook: Update Gitea Configuration
hosts: production # Purpose: Update Gitea app.ini configuration to fix performance issues
become: no # Usage:
gather_facts: yes # ansible-playbook -i inventory/production.yml playbooks/update-gitea-config.yml \
# --vault-password-file secrets/.vault_pass
- name: Update Gitea Configuration
hosts: production
vars: vars:
gitea_stack_path: "{{ stacks_base_path }}/gitea" gitea_stack_path: "{{ stacks_base_path }}/gitea"
gitea_url: "https://{{ gitea_domain }}"
gitea_app_ini_path: "{{ gitea_stack_path }}/app.ini"
gitea_app_ini_container_path: "/data/gitea/conf/app.ini"
tasks: tasks:
- name: Copy updated docker-compose.yml to production server - name: Verify Gitea container exists
copy:
src: "{{ playbook_dir }}/../../stacks/gitea/docker-compose.yml"
dest: "{{ gitea_stack_path }}/docker-compose.yml"
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: '0644'
- name: Restart Gitea stack with updated configuration
community.docker.docker_compose_v2:
project_src: "{{ gitea_stack_path }}"
state: present
pull: never
recreate: always
remove_orphans: no
register: gitea_restart
- name: Wait for Gitea to be ready
wait_for:
timeout: 60
when: gitea_restart.changed
- name: Verify Gitea Actions configuration
shell: | shell: |
docker exec gitea cat /data/gitea/conf/app.ini 2>/dev/null | grep -A 3 "\[actions\]" || echo "Config not accessible" docker compose -f {{ gitea_stack_path }}/docker-compose.yml ps gitea | grep -q "gitea"
register: gitea_config register: gitea_exists
changed_when: false changed_when: false
failed_when: false
- name: Fail if Gitea container does not exist
fail:
msg: "Gitea container does not exist. Please deploy Gitea stack first."
when: gitea_exists.rc != 0
- name: Get database configuration from environment
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml exec -T gitea env | grep -E "^GITEA__database__" || true
register: gitea_db_env
changed_when: false
failed_when: false
- name: Parse database configuration
set_fact:
gitea_db_type: "{{ (gitea_db_env.stdout | default('') | regex_search('GITEA__database__DB_TYPE=([^\n]+)', '\\1') or ['postgres']) | first }}"
gitea_db_host: "{{ (gitea_db_env.stdout | default('') | regex_search('GITEA__database__HOST=([^\n]+)', '\\1') or ['postgres:5432']) | first }}"
gitea_db_name: "{{ (gitea_db_env.stdout | default('') | regex_search('GITEA__database__NAME=([^\n]+)', '\\1') or ['gitea']) | first }}"
gitea_db_user: "{{ (gitea_db_env.stdout | default('') | regex_search('GITEA__database__USER=([^\n]+)', '\\1') or ['gitea']) | first }}"
gitea_db_passwd: "{{ (gitea_db_env.stdout | default('') | regex_search('GITEA__database__PASSWD=([^\n]+)', '\\1') or ['gitea_password']) | first }}"
- name: Get Gitea server configuration from environment
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml exec -T gitea env | grep -E "^GITEA__server__" || true
register: gitea_server_env
changed_when: false
failed_when: false
- name: Parse server configuration
set_fact:
gitea_domain_parsed: "{{ (gitea_server_env.stdout | default('') | regex_search('GITEA__server__DOMAIN=([^\n]+)', '\\1') or [gitea_domain | default('git.michaelschiemer.de')]) | first }}"
ssh_port_parsed: "{{ (gitea_server_env.stdout | default('') | regex_search('GITEA__server__SSH_PORT=([^\n]+)', '\\1') or ['2222']) | first }}"
- name: Set final configuration variables
set_fact:
gitea_domain: "{{ gitea_domain_parsed }}"
ssh_port: "{{ ssh_port_parsed }}"
ssh_listen_port: "{{ ssh_port_parsed }}"
- name: Extract database host and port
set_fact:
gitea_db_hostname: "{{ gitea_db_host.split(':')[0] }}"
gitea_db_port: "{{ (gitea_db_host.split(':')[1]) | default('5432') }}"
- name: Set Redis password
set_fact:
redis_password: "{{ vault_gitea_redis_password | default(vault_redis_password | default('gitea_redis_password')) }}"
- name: Generate app.ini from template
template:
src: ../templates/gitea-app.ini.j2
dest: "{{ gitea_app_ini_path }}"
mode: '0644'
vars:
postgres_db: "{{ gitea_db_name }}"
postgres_user: "{{ gitea_db_user }}"
postgres_password: "{{ gitea_db_passwd }}"
gitea_domain: "{{ gitea_domain }}"
ssh_port: "{{ ssh_port }}"
ssh_listen_port: "{{ ssh_listen_port }}"
disable_registration: true
redis_password: "{{ redis_password }}"
- name: Copy app.ini to Gitea container
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml cp {{ gitea_app_ini_path }} gitea:{{ gitea_app_ini_container_path }}
ignore_errors: yes ignore_errors: yes
- name: Display Gitea Actions configuration - name: Wait for container to be ready for exec
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml exec -T gitea true
register: container_ready
until: container_ready.rc == 0
retries: 30
delay: 2
changed_when: false
- name: Set correct permissions on app.ini in container
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml exec -T --user git gitea chown 1000:1000 {{ gitea_app_ini_container_path }} && \
docker compose -f {{ gitea_stack_path }}/docker-compose.yml exec -T --user git gitea chmod 644 {{ gitea_app_ini_container_path }}
- name: Restart Gitea container
shell: |
docker compose -f {{ gitea_stack_path }}/docker-compose.yml restart gitea
- name: Wait for Gitea to be ready after restart
uri:
url: "{{ gitea_url }}/api/healthz"
method: GET
status_code: [200]
validate_certs: false
timeout: 10
register: gitea_health_after_restart
until: gitea_health_after_restart.status == 200
retries: 30
delay: 5
changed_when: false
- name: Display success message
debug: debug:
msg: msg: |
- "=== Gitea Configuration Update Complete ===" Gitea configuration has been updated successfully!
- "Container restarted: {{ 'Yes' if gitea_restart.changed else 'No' }}"
- "" Changes applied:
- "Current Actions configuration:" - Redis cache enabled (persistent, survives container restarts)
- "{{ gitea_config.stdout if gitea_config.stdout else 'Could not read config (container may still be starting)' }}" - Redis sessions enabled (better performance and scalability)
- "" - Redis queue enabled (persistent job processing)
- "The DEFAULT_ACTIONS_URL should now point to your Gitea instance instead of GitHub." - Database connection pooling configured
- Connection limits set to prevent "Connection reset by peer" errors
Gitea should now be more stable and perform better with Redis.

View File

@@ -30,6 +30,16 @@ vault_git_token: "change-me-gitea-personal-access-token"
# vault_git_username: "your-gitea-username" # vault_git_username: "your-gitea-username"
# vault_git_password: "your-gitea-password" # vault_git_password: "your-gitea-password"
# Gitea Admin Credentials (for initial setup)
# Required for automated Gitea initial configuration
vault_gitea_admin_username: "admin"
vault_gitea_admin_password: "change-me-secure-gitea-admin-password"
vault_gitea_admin_email: "kontakt@michaelschiemer.de"
# Gitea Redis Credentials
# Required for Redis cache, sessions, and queue
vault_gitea_redis_password: "change-me-secure-gitea-redis-password"
# Optional: Additional Secrets # Optional: Additional Secrets
vault_encryption_key: "change-me-encryption-key" vault_encryption_key: "change-me-encryption-key"
vault_session_secret: "change-me-session-secret" vault_session_secret: "change-me-session-secret"

View File

@@ -21,13 +21,22 @@ HTTP_ADDR = 0.0.0.0
HTTP_PORT = 3000 HTTP_PORT = 3000
ROOT_URL = https://{{ gitea_domain }}/ ROOT_URL = https://{{ gitea_domain }}/
PUBLIC_URL_DETECTION = auto PUBLIC_URL_DETECTION = auto
;; Performance settings for handling concurrent requests
LFS_START_SERVER = true
LFS_CONTENT_PATH = data/lfs
LFS_JWT_SECRET =
;; Increase timeouts for better stability under load
READ_TIMEOUT = 60s
WRITE_TIMEOUT = 60s
;; SSH Configuration ;; SSH Configuration
;; Note: SSH_LISTEN_PORT should match the port exposed in docker-compose.yml
;; If SSH is not needed, set DISABLE_SSH = true and START_SSH_SERVER = false
DISABLE_SSH = false DISABLE_SSH = false
START_SSH_SERVER = true START_SSH_SERVER = false
SSH_DOMAIN = {{ gitea_domain }} SSH_DOMAIN = {{ gitea_domain }}
SSH_PORT = 22 SSH_PORT = {{ ssh_port | default(2222) }}
SSH_LISTEN_PORT = 22 SSH_LISTEN_PORT = {{ ssh_listen_port | default(2222) }}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Database Configuration ;; Database Configuration
@@ -39,30 +48,45 @@ NAME = {{ postgres_db | default('gitea') }}
USER = {{ postgres_user | default('gitea') }} USER = {{ postgres_user | default('gitea') }}
PASSWD = {{ postgres_password | default('gitea_password') }} PASSWD = {{ postgres_password | default('gitea_password') }}
SSL_MODE = disable SSL_MODE = disable
;; Connection Pool Settings - Prevents "Connection reset by peer" errors
;; Increased limits for handling concurrent requests
MAX_OPEN_CONNS = 200
MAX_IDLE_CONNS = 50
CONN_MAX_LIFETIME = 600
CONN_MAX_IDLE_TIME = 300
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Cache Configuration ;; Cache Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[cache] [cache]
ENABLED = false ENABLED = true
ADAPTER = memory ADAPTER = redis
HOST = redis:6379
PASSWORD = {{ redis_password | default('gitea_redis_password') }}
DB = 0
;; Redis cache for better performance and persistence
;; Cache survives container restarts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Session Configuration ;; Session Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[session] [session]
PROVIDER = file PROVIDER = redis
PROVIDER_CONFIG = data/sessions PROVIDER_CONFIG = network=tcp,addr=redis:6379,password={{ redis_password | default('gitea_redis_password') }},db=0,pool_size=100,idle_timeout=180
COOKIE_SECURE = true COOKIE_SECURE = true
COOKIE_NAME = i_like_gitea COOKIE_NAME = i_like_gitea
GC_INTERVAL_TIME = 86400 GC_INTERVAL_TIME = 86400
SESSION_LIFE_TIME = 86400 SESSION_LIFE_TIME = 86400
;; Redis sessions for better performance and scalability
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Queue Configuration ;; Queue Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[queue] [queue]
TYPE = channel TYPE = redis
CONN_STR = redis://:{{ redis_password | default('gitea_redis_password') }}@redis:6379/0
;; Redis queue for persistent job processing
;; Jobs survive container restarts
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Service Configuration ;; Service Configuration
@@ -79,3 +103,10 @@ ENABLED = true
;; Do NOT set DEFAULT_ACTIONS_URL to a custom URL - it's not supported ;; Do NOT set DEFAULT_ACTIONS_URL to a custom URL - it's not supported
;; Leaving it unset or setting to "self" will use the current instance ;; Leaving it unset or setting to "self" will use the current instance
;DEFAULT_ACTIONS_URL = self ;DEFAULT_ACTIONS_URL = self
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Security Configuration
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
[security]
;; Set INSTALL_LOCK to true to skip the initial setup page
INSTALL_LOCK = true

View File

@@ -411,17 +411,54 @@ docker compose logs redis
### Performance Issues ### Performance Issues
```bash **If Gitea has frequent outages or connection issues:**
# Check MySQL slow queries
docker exec gitea-mysql tail -100 /var/log/mysql/slow-queries.log
# Analyze MySQL performance 1. **Update Gitea Configuration** (Recommended):
docker exec gitea-mysql mysql -u root -p$MYSQL_ROOT_PASSWORD \ ```bash
-e "SHOW PROCESSLIST;" cd deployment/ansible
ansible-playbook -i inventory/production.yml \
playbooks/update-gitea-config.yml \
--vault-password-file secrets/.vault_pass
```
# Check Redis memory usage This playbook will:
docker exec gitea-redis redis-cli -a $REDIS_PASSWORD INFO memory - Enable Redis cache for better performance and persistence
``` - Configure database connection pooling
- Set connection limits to prevent "Connection reset by peer" errors
2. **Manual Troubleshooting**:
```bash
# Check PostgreSQL slow queries
docker exec gitea-postgres psql -U gitea -d gitea -c "SELECT * FROM pg_stat_activity;"
# Check container resource usage
docker stats gitea gitea-postgres gitea-redis
# Check Gitea logs for errors
docker compose logs --tail 100 gitea | grep -i error
# Check Redis connection
docker exec gitea-redis redis-cli -a $REDIS_PASSWORD ping
```
### Known Issues
**Bad Gateway after many rapid requests (15-20 reloads):**
- **Status**: Known issue, non-critical
- **Symptoms**: Gitea returns "Bad Gateway" after 15-20 rapid page reloads, recovers after a few seconds
- **Impact**: Low - Gitea is functional for normal usage
- **Possible causes**:
- Container restart during high load
- Connection pool exhaustion (mitigated with increased limits)
- Traefik service discovery delay in host network mode
- **Workarounds**:
- Wait a few seconds and retry
- Use Redis cache (already enabled) for better performance
- Consider adding rate limiting if needed (see Traefik middlewares)
- **Future improvements**:
- Monitor and optimize connection pool usage
- Consider adding rate limiting middleware for Gitea
- Investigate Traefik service discovery in host network mode
### Reset Admin Password ### Reset Admin Password

View File

@@ -5,6 +5,7 @@ services:
restart: unless-stopped restart: unless-stopped
depends_on: depends_on:
- postgres - postgres
- redis
networks: networks:
- traefik-public - traefik-public
- gitea-internal - gitea-internal
@@ -18,10 +19,14 @@ services:
- GITEA__database__NAME=${POSTGRES_DB:-gitea} - GITEA__database__NAME=${POSTGRES_DB:-gitea}
- GITEA__database__USER=${POSTGRES_USER:-gitea} - GITEA__database__USER=${POSTGRES_USER:-gitea}
- GITEA__database__PASSWD=${POSTGRES_PASSWORD:-gitea_password} - GITEA__database__PASSWD=${POSTGRES_PASSWORD:-gitea_password}
- GITEA__cache__ENABLED=false - GITEA__cache__ENABLED=true
- GITEA__cache__ADAPTER=memory - GITEA__cache__ADAPTER=redis
- GITEA__session__PROVIDER=file - GITEA__cache__HOST=redis:6379
- GITEA__queue__TYPE=channel - GITEA__cache__PASSWORD=${REDIS_PASSWORD:-gitea_redis_password}
- GITEA__session__PROVIDER=redis
- GITEA__session__PROVIDER_CONFIG=network=tcp,addr=redis:6379,password=${REDIS_PASSWORD:-gitea_redis_password},db=0,pool_size=100,idle_timeout=180
- GITEA__queue__TYPE=redis
- GITEA__queue__CONN_STR=redis://:${REDIS_PASSWORD:-gitea_redis_password}@redis:6379/0
- GITEA__server__DOMAIN=${GITEA_DOMAIN:-git.michaelschiemer.de} - GITEA__server__DOMAIN=${GITEA_DOMAIN:-git.michaelschiemer.de}
- GITEA__server__ROOT_URL=https://${GITEA_DOMAIN:-git.michaelschiemer.de}/ - GITEA__server__ROOT_URL=https://${GITEA_DOMAIN:-git.michaelschiemer.de}/
- GITEA__server__SSH_DOMAIN=${GITEA_DOMAIN:-git.michaelschiemer.de} - GITEA__server__SSH_DOMAIN=${GITEA_DOMAIN:-git.michaelschiemer.de}
@@ -32,8 +37,6 @@ services:
- gitea-data:/data - gitea-data:/data
- /etc/timezone:/etc/timezone:ro - /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro - /etc/localtime:/etc/localtime:ro
ports:
- "2222:22" # SSH for Git operations
labels: labels:
- "traefik.enable=true" - "traefik.enable=true"
@@ -47,6 +50,8 @@ services:
# Service # Service
- "traefik.http.services.gitea.loadbalancer.server.port=3000" - "traefik.http.services.gitea.loadbalancer.server.port=3000"
# Use container name explicitly for host network mode
- "traefik.http.services.gitea.loadbalancer.server.scheme=http"
# Middleware # Middleware
- "traefik.http.routers.gitea.middlewares=default-chain@file" - "traefik.http.routers.gitea.middlewares=default-chain@file"
@@ -68,6 +73,7 @@ services:
- POSTGRES_DB=gitea - POSTGRES_DB=gitea
- POSTGRES_USER=gitea - POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea_password - POSTGRES_PASSWORD=gitea_password
command: postgres -c max_connections=300
volumes: volumes:
- postgres-data:/var/lib/postgresql/data - postgres-data:/var/lib/postgresql/data
healthcheck: healthcheck:
@@ -77,32 +83,36 @@ services:
retries: 3 retries: 3
start_period: 30s start_period: 30s
# redis (disabled for now; Gitea configured to not use redis) redis:
# redis: image: redis:7-alpine
# image: redis:7 container_name: gitea-redis
# container_name: gitea-redis restart: unless-stopped
# restart: unless-stopped networks:
# networks: - gitea-internal
# - gitea-internal environment:
# environment: - TZ=Europe/Berlin
# - TZ=Europe/Berlin command: >
# volumes: redis-server
# - redis-data:/data --requirepass ${REDIS_PASSWORD:-gitea_redis_password}
# command: redis-server --appendonly yes --appendonly yes
# healthcheck: --maxmemory 512mb
# test: ["CMD", "redis-cli", "ping"] --maxmemory-policy allkeys-lru
# interval: 30s volumes:
# timeout: 10s - redis-data:/data
# retries: 3 healthcheck:
# start_period: 10s test: ["CMD", "redis-cli", "--raw", "incr", "ping"]
interval: 30s
timeout: 10s
retries: 3
start_period: 10s
volumes: volumes:
gitea-data: gitea-data:
name: gitea-data name: gitea-data
postgres-data: postgres-data:
name: gitea-postgres-data name: gitea-postgres-data
# redis-data: redis-data:
# name: gitea-redis-data name: gitea-redis-data
networks: networks:
traefik-public: traefik-public:

View File

@@ -1,15 +1,20 @@
http: # Gitea configuration is now handled via Docker labels in docker-compose.yml
routers: # This file is kept for reference but is not used
gitea: # Traefik will automatically discover Gitea via Docker labels and use the container IP
rule: Host(`git.michaelschiemer.de`) # when running in host network mode
entrypoints: #
- websecure # http:
service: gitea # routers:
tls: # gitea:
certResolver: letsencrypt # rule: Host(`git.michaelschiemer.de`)
priority: 100 # entrypoints:
services: # - websecure
gitea: # service: gitea
loadBalancer: # tls:
servers: # certResolver: letsencrypt
- url: http://gitea:3000 # priority: 100
# services:
# gitea:
# loadBalancer:
# servers:
# - url: http://gitea:3000