first commit
This commit is contained in:
commit
cd9f0b8e72
22
.env.example
Normal file
22
.env.example
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# Скопируйте в .env и измените значения перед развертыванием
|
||||||
|
# cp .env.example .env
|
||||||
|
|
||||||
|
# Домен или IP сервера (без http/https)
|
||||||
|
GITEA_DOMAIN=localhost
|
||||||
|
|
||||||
|
# Порт веб-интерфейса Gitea
|
||||||
|
GITEA_HTTP_PORT=3000
|
||||||
|
|
||||||
|
# Порт SSH для git clone/push
|
||||||
|
GITEA_SSH_PORT=2222
|
||||||
|
|
||||||
|
# Версия образа Gitea
|
||||||
|
GITEA_VERSION=1.22.6
|
||||||
|
|
||||||
|
# База данных PostgreSQL
|
||||||
|
POSTGRES_USER=gitea
|
||||||
|
POSTGRES_PASSWORD=change_me_strong_password
|
||||||
|
POSTGRES_DB=gitea
|
||||||
|
|
||||||
|
# Часовой пояс
|
||||||
|
TZ=Europe/Moscow
|
||||||
14
.gitattributes
vendored
Normal file
14
.gitattributes
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Enforce LF line endings
|
||||||
|
* text=auto eol=lf
|
||||||
|
|
||||||
|
# Shell scripts must be executable with LF
|
||||||
|
*.sh text eol=lf
|
||||||
|
*.ps1 text eol=lf
|
||||||
|
|
||||||
|
# Config and docs
|
||||||
|
*.yml text eol=lf
|
||||||
|
*.yaml text eol=lf
|
||||||
|
*.md text eol=lf
|
||||||
|
*.env* text eol=lf
|
||||||
|
*.service text eol=lf
|
||||||
|
.gitignore text eol=lf
|
||||||
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
.env
|
||||||
|
backups/
|
||||||
314
README.md
Normal file
314
README.md
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
# Развёртывание Gitea
|
||||||
|
|
||||||
|
Docker Compose-стек для запуска [Gitea](https://about.gitea.com/) с PostgreSQL. Включает скрипты управления для Linux и Windows.
|
||||||
|
|
||||||
|
## Состав
|
||||||
|
|
||||||
|
| Компонент | Образ | Назначение |
|
||||||
|
|-----------|-------|------------|
|
||||||
|
| Gitea | `gitea/gitea` | Git-сервер, веб-интерфейс, SSH |
|
||||||
|
| PostgreSQL | `postgres:16-alpine` | База данных |
|
||||||
|
|
||||||
|
Данные хранятся в Docker-томах `gitea_gitea_data` и `gitea_postgres_data` и сохраняются при перезапуске контейнеров.
|
||||||
|
|
||||||
|
## Требования
|
||||||
|
|
||||||
|
- **Docker** с плагином **Compose v2** (`docker compose`)
|
||||||
|
- Windows: [Docker Desktop](https://www.docker.com/products/docker-desktop/)
|
||||||
|
- Linux: Docker Engine + `docker-compose-plugin`
|
||||||
|
- Свободные порты (по умолчанию `3000` — HTTP, `2222` — SSH)
|
||||||
|
|
||||||
|
## Быстрый старт
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone <url-репозитория> gitea
|
||||||
|
cd gitea
|
||||||
|
|
||||||
|
chmod +x deploy.sh
|
||||||
|
./deploy.sh install
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт задаст вопросы по настройке (домен, порты, пароль БД и др.). Enter — принять значение по умолчанию в скобках. Для пароля PostgreSQL Enter — автогенерация.
|
||||||
|
|
||||||
|
Без интерактивного режима (CI, автоматизация):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh install -y
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (PowerShell)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
cd D:\shared\Проекты\gitea
|
||||||
|
|
||||||
|
.\deploy.ps1 install
|
||||||
|
```
|
||||||
|
|
||||||
|
Без интерактивного режима:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\deploy.ps1 install -NonInteractive
|
||||||
|
```
|
||||||
|
|
||||||
|
После запуска откройте в браузере:
|
||||||
|
|
||||||
|
- **Web UI:** `http://localhost:3000` (или ваш `GITEA_DOMAIN:GITEA_HTTP_PORT`)
|
||||||
|
- **Git SSH:** `ssh://git@localhost:2222`
|
||||||
|
|
||||||
|
## Первоначальная настройка
|
||||||
|
|
||||||
|
При первом входе в веб-интерфейс Gitea откроется мастер установки:
|
||||||
|
|
||||||
|
1. Убедитесь, что тип БД — **PostgreSQL** (уже настроено через переменные окружения).
|
||||||
|
2. Создайте учётную запись администратора.
|
||||||
|
3. Задайте название сайта и прочие параметры по необходимости.
|
||||||
|
|
||||||
|
> База данных и подключение к ней уже сконфигурированы в `docker-compose.yml`. На шаге настройки БД можно оставить значения по умолчанию или проверить, что они совпадают с `.env`.
|
||||||
|
|
||||||
|
## Конфигурация
|
||||||
|
|
||||||
|
При `./deploy.sh install` или `.\deploy.ps1 install` создаётся файл `.env` на основе ваших ответов. Можно также создать его вручную из `.env.example`.
|
||||||
|
|
||||||
|
Интерактивно запрашиваются:
|
||||||
|
|
||||||
|
| Переменная | По умолчанию | Описание |
|
||||||
|
|------------|--------------|----------|
|
||||||
|
| `GITEA_DOMAIN` | `localhost` | Домен или IP сервера (без `http://`) |
|
||||||
|
| `GITEA_HTTP_PORT` | `3000` | Порт веб-интерфейса |
|
||||||
|
| `GITEA_SSH_PORT` | `2222` | Внешний порт SSH для Git |
|
||||||
|
| `GITEA_VERSION` | `1.22.6` | Версия образа Gitea |
|
||||||
|
| `POSTGRES_USER` | `gitea` | Пользователь PostgreSQL |
|
||||||
|
| `POSTGRES_PASSWORD` | автогенерация | Пароль PostgreSQL (скрытый ввод) |
|
||||||
|
| `POSTGRES_DB` | `gitea` | Имя базы данных |
|
||||||
|
| `TZ` | `Europe/Moscow` | Часовой пояс |
|
||||||
|
|
||||||
|
Если `.env` уже существует, скрипт спросит, пересоздать ли конфигурацию.
|
||||||
|
|
||||||
|
Пример для продакшена:
|
||||||
|
|
||||||
|
```env
|
||||||
|
GITEA_DOMAIN=git.example.com
|
||||||
|
GITEA_HTTP_PORT=3000
|
||||||
|
GITEA_SSH_PORT=2222
|
||||||
|
POSTGRES_PASSWORD=your_strong_secret_password
|
||||||
|
TZ=Europe/Moscow
|
||||||
|
```
|
||||||
|
|
||||||
|
## Управление
|
||||||
|
|
||||||
|
Помимо универсального `deploy.sh` / `deploy.ps1` доступны отдельные скрипты:
|
||||||
|
|
||||||
|
| Скрипт (Linux) | Скрипт (Windows) | Описание |
|
||||||
|
|----------------|------------------|----------|
|
||||||
|
| `start.sh` | `start.ps1` | Запуск контейнеров |
|
||||||
|
| `stop.sh` | `stop.ps1` | Остановка контейнеров |
|
||||||
|
| `install-service.sh` | `install-service.ps1` | Автозапуск при загрузке системы |
|
||||||
|
| `remove-service.sh` | `remove-service.ps1` | Удаление из автозагрузки |
|
||||||
|
| `uninstall.sh` | `uninstall.ps1` | Удаление контейнеров |
|
||||||
|
| `reinstall.sh` | `reinstall.ps1` | Переустановка (обновление образов) |
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x *.sh
|
||||||
|
|
||||||
|
./start.sh
|
||||||
|
./stop.sh
|
||||||
|
|
||||||
|
sudo ./install-service.sh # systemd: автозапуск
|
||||||
|
sudo ./remove-service.sh # удалить из systemd
|
||||||
|
|
||||||
|
./uninstall.sh # удалить контейнеры (данные сохраняются)
|
||||||
|
./uninstall.sh --purge # удалить контейнеры и данные
|
||||||
|
|
||||||
|
./reinstall.sh # пересоздать контейнеры, данные сохраняются
|
||||||
|
./reinstall.sh --purge # чистая переустановка
|
||||||
|
```
|
||||||
|
|
||||||
|
После `install-service.sh` управление через systemd:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl start gitea
|
||||||
|
sudo systemctl stop gitea
|
||||||
|
sudo systemctl status gitea
|
||||||
|
sudo systemctl enable gitea
|
||||||
|
sudo systemctl disable gitea
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\start.ps1
|
||||||
|
.\stop.ps1
|
||||||
|
|
||||||
|
# Запуск от администратора:
|
||||||
|
.\install-service.ps1 # задача в планировщике (автозапуск)
|
||||||
|
.\remove-service.ps1 # удалить задачу
|
||||||
|
|
||||||
|
.\uninstall.ps1 # удалить контейнеры (данные сохраняются)
|
||||||
|
.\uninstall.ps1 -Purge # удалить контейнеры и данные
|
||||||
|
|
||||||
|
.\reinstall.ps1 # пересоздать контейнеры
|
||||||
|
.\reinstall.ps1 -Purge # чистая переустановка
|
||||||
|
```
|
||||||
|
|
||||||
|
### Универсальный deploy (все команды)
|
||||||
|
|
||||||
|
#### Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh install # Первичное развёртывание
|
||||||
|
./deploy.sh start # Запуск
|
||||||
|
./deploy.sh stop # Остановка
|
||||||
|
./deploy.sh restart # Перезапуск
|
||||||
|
./deploy.sh update # Обновление образов
|
||||||
|
./deploy.sh status # Статус контейнеров
|
||||||
|
./deploy.sh logs # Логи Gitea (follow)
|
||||||
|
./deploy.sh backup # Резервная копия
|
||||||
|
./deploy.sh restore backups/gitea-backup-20260101-120000.tar.gz
|
||||||
|
./deploy.sh uninstall # Удаление контейнеров (данные сохраняются)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Windows
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\deploy.ps1 install
|
||||||
|
.\deploy.ps1 start
|
||||||
|
.\deploy.ps1 stop
|
||||||
|
.\deploy.ps1 restart
|
||||||
|
.\deploy.ps1 update
|
||||||
|
.\deploy.ps1 status
|
||||||
|
.\deploy.ps1 logs
|
||||||
|
.\deploy.ps1 backup
|
||||||
|
.\deploy.ps1 restore -BackupFile backups\gitea-backup-20260101-120000.tar.gz
|
||||||
|
.\deploy.ps1 uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
## Резервное копирование и восстановление
|
||||||
|
|
||||||
|
### Создание бэкапа
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh backup
|
||||||
|
# или
|
||||||
|
.\deploy.ps1 backup
|
||||||
|
```
|
||||||
|
|
||||||
|
Архив сохраняется в каталог `backups/` с именем `gitea-backup-YYYYMMDD-HHMMSS.tar.gz`. В архив входят Docker-тома с данными Gitea и PostgreSQL.
|
||||||
|
|
||||||
|
### Восстановление
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh restore backups/gitea-backup-20260101-120000.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\deploy.ps1 restore -BackupFile backups\gitea-backup-20260101-120000.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
> Восстановление останавливает контейнеры и **перезаписывает** текущие данные. Перед выполнением скрипт запросит подтверждение.
|
||||||
|
|
||||||
|
## Обновление Gitea
|
||||||
|
|
||||||
|
1. При необходимости измените `GITEA_VERSION` в `.env`.
|
||||||
|
2. Выполните обновление:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh update
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт загрузит новые образы и перезапустит контейнеры. Данные в томах сохраняются.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── docker-compose.yml # Описание сервисов
|
||||||
|
├── .env.example # Шаблон переменных окружения
|
||||||
|
├── deploy.sh / deploy.ps1 # Универсальный скрипт управления
|
||||||
|
├── start.sh / start.ps1 # Запуск
|
||||||
|
├── stop.sh / stop.ps1 # Остановка
|
||||||
|
├── install-service.sh / install-service.ps1 # Автозапуск
|
||||||
|
├── remove-service.sh / remove-service.ps1 # Удаление автозапуска
|
||||||
|
├── uninstall.sh / uninstall.ps1 # Удаление
|
||||||
|
├── reinstall.sh / reinstall.ps1 # Переустановка
|
||||||
|
├── lib/ # Общие функции
|
||||||
|
├── systemd/ # Шаблон unit-файла для Linux
|
||||||
|
├── backups/ # Резервные копии (создаётся автоматически)
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Продакшен
|
||||||
|
|
||||||
|
### HTTPS
|
||||||
|
|
||||||
|
Для продакшена рекомендуется разместить Gitea за reverse proxy (Nginx, Caddy, Traefik) с TLS-сертификатом. После настройки прокси обновите в `.env`:
|
||||||
|
|
||||||
|
```env
|
||||||
|
GITEA_DOMAIN=git.example.com
|
||||||
|
GITEA_HTTP_PORT=3000
|
||||||
|
```
|
||||||
|
|
||||||
|
И задайте корректный `ROOT_URL` — при необходимости добавьте в `docker-compose.yml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
GITEA__server__ROOT_URL: https://git.example.com/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Firewall
|
||||||
|
|
||||||
|
Откройте только нужные порты:
|
||||||
|
|
||||||
|
- `GITEA_HTTP_PORT` — веб-интерфейс (или только через reverse proxy на 443)
|
||||||
|
- `GITEA_SSH_PORT` — Git по SSH
|
||||||
|
|
||||||
|
### Полное удаление данных
|
||||||
|
|
||||||
|
Контейнеры удаляются командой `uninstall`, но тома остаются. Для полной очистки:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose down
|
||||||
|
docker volume rm gitea_gitea_data gitea_postgres_data
|
||||||
|
```
|
||||||
|
|
||||||
|
## Устранение неполадок
|
||||||
|
|
||||||
|
### Контейнер Gitea не стартует
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose logs gitea
|
||||||
|
docker compose logs db
|
||||||
|
```
|
||||||
|
|
||||||
|
Убедитесь, что `POSTGRES_PASSWORD` задан в `.env` и PostgreSQL прошёл healthcheck.
|
||||||
|
|
||||||
|
### Порт занят
|
||||||
|
|
||||||
|
Измените `GITEA_HTTP_PORT` или `GITEA_SSH_PORT` в `.env` и перезапустите:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./deploy.sh restart
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSH clone не работает
|
||||||
|
|
||||||
|
Проверьте, что порт `GITEA_SSH_PORT` проброшен и доступен с клиента:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -p 2222 git@your-server
|
||||||
|
```
|
||||||
|
|
||||||
|
В Gitea SSH-домен должен совпадать с `GITEA_DOMAIN` из `.env`.
|
||||||
|
|
||||||
|
### Сброс пароля администратора
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose exec gitea gitea admin user list
|
||||||
|
docker compose exec gitea gitea admin user change-password --username admin --password newpassword
|
||||||
|
```
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
Gitea распространяется под лицензией MIT. Данный репозиторий содержит только конфигурацию развёртывания.
|
||||||
206
deploy.ps1
Normal file
206
deploy.ps1
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Скрипт развертывания Gitea через Docker Compose (Windows)
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\deploy.ps1 install
|
||||||
|
.\deploy.ps1 install -NonInteractive
|
||||||
|
.\deploy.ps1 update
|
||||||
|
.\deploy.ps1 backup
|
||||||
|
#>
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Position = 0)]
|
||||||
|
[ValidateSet("install", "start", "stop", "restart", "update", "status", "logs", "backup", "restore", "uninstall", "help")]
|
||||||
|
[string]$Command = "install",
|
||||||
|
|
||||||
|
[Parameter(Position = 1)]
|
||||||
|
[string]$BackupFile,
|
||||||
|
|
||||||
|
[switch]$NonInteractive
|
||||||
|
)
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
function Show-Usage {
|
||||||
|
@"
|
||||||
|
Использование: .\deploy.ps1 [команда] [опции]
|
||||||
|
|
||||||
|
Команды:
|
||||||
|
install — первичное развертывание (по умолчанию)
|
||||||
|
start — запуск контейнеров
|
||||||
|
stop — остановка контейнеров
|
||||||
|
restart — перезапуск
|
||||||
|
update — обновление образов и перезапуск
|
||||||
|
status — статус контейнеров
|
||||||
|
logs — просмотр логов Gitea
|
||||||
|
backup — резервная копия данных
|
||||||
|
restore — восстановление из backup
|
||||||
|
uninstall — остановка и удаление контейнеров (данные сохраняются)
|
||||||
|
|
||||||
|
Опции install:
|
||||||
|
-NonInteractive Без интерактивных вопросов (значения из .env.example, пароль — автогенерация)
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
.\deploy.ps1 install
|
||||||
|
.\deploy.ps1 install -NonInteractive
|
||||||
|
.\deploy.ps1 update
|
||||||
|
.\deploy.ps1 backup
|
||||||
|
.\deploy.ps1 restore -BackupFile backups\gitea-backup-20260101.tar.gz
|
||||||
|
"@
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Install {
|
||||||
|
Test-Dependencies
|
||||||
|
Invoke-SetupEnvInteractive -NonInteractive:$NonInteractive
|
||||||
|
|
||||||
|
Write-Info "Загрузка образов..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
Write-Info "Запуск Gitea..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
$domain = if ($env:GITEA_DOMAIN) { $env:GITEA_DOMAIN } else { "localhost" }
|
||||||
|
$httpPort = if ($env:GITEA_HTTP_PORT) { $env:GITEA_HTTP_PORT } else { "3000" }
|
||||||
|
$sshPort = if ($env:GITEA_SSH_PORT) { $env:GITEA_SSH_PORT } else { "2222" }
|
||||||
|
|
||||||
|
Write-Info "Gitea развернута!"
|
||||||
|
Write-Info " Web: http://${domain}:${httpPort}"
|
||||||
|
Write-Info " SSH: ssh://git@${domain}:${sshPort}"
|
||||||
|
Write-Info "При первом входе откройте Web UI и завершите мастер настройки."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Start {
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Stop {
|
||||||
|
Test-Dependencies
|
||||||
|
docker compose down
|
||||||
|
Write-Info "Контейнеры остановлены."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Restart {
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
docker compose restart
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Update {
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
Write-Info "Обновление образов..."
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
Write-Info "Обновление завершено."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Status {
|
||||||
|
Test-Dependencies
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Logs {
|
||||||
|
Test-Dependencies
|
||||||
|
docker compose logs -f --tail=100 gitea
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Backup {
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
|
||||||
|
$backupDir = Join-Path $script:ScriptDir "backups"
|
||||||
|
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
|
||||||
|
$backupFile = Join-Path $backupDir "gitea-backup-$timestamp.tar.gz"
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Force -Path $backupDir | Out-Null
|
||||||
|
|
||||||
|
Write-Info "Создание резервной копии: $backupFile"
|
||||||
|
|
||||||
|
docker run --rm `
|
||||||
|
-v gitea_gitea_data:/gitea_data:ro `
|
||||||
|
-v gitea_postgres_data:/postgres_data:ro `
|
||||||
|
-v "${backupDir}:/backup" `
|
||||||
|
alpine:3.20 `
|
||||||
|
sh -c "tar czf /backup/gitea-backup-$timestamp.tar.gz -C / gitea_data postgres_data"
|
||||||
|
|
||||||
|
Write-Info "Резервная копия сохранена: $backupFile"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Restore {
|
||||||
|
if (-not $BackupFile -or -not (Test-Path $BackupFile)) {
|
||||||
|
throw "Укажите существующий файл: .\deploy.ps1 restore -BackupFile backups\gitea-backup-....tar.gz"
|
||||||
|
}
|
||||||
|
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
|
||||||
|
Write-Warn "Восстановление перезапишет текущие данные!"
|
||||||
|
$confirm = Read-Host "Продолжить? [y/N]"
|
||||||
|
if ($confirm -notmatch '^[Yy]$') {
|
||||||
|
Write-Info "Отменено."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Остановка контейнеров..."
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
$backupDir = (Resolve-Path (Split-Path $BackupFile -Parent)).Path
|
||||||
|
$backupName = Split-Path $BackupFile -Leaf
|
||||||
|
|
||||||
|
Write-Info "Восстановление из $BackupFile..."
|
||||||
|
docker run --rm `
|
||||||
|
-v gitea_gitea_data:/gitea_data `
|
||||||
|
-v gitea_postgres_data:/postgres_data `
|
||||||
|
-v "${backupDir}:/backup:ro" `
|
||||||
|
alpine:3.20 `
|
||||||
|
sh -c "cd / && tar xzf /backup/$backupName"
|
||||||
|
|
||||||
|
Write-Info "Запуск контейнеров..."
|
||||||
|
docker compose up -d
|
||||||
|
Write-Info "Восстановление завершено."
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-Uninstall {
|
||||||
|
Test-Dependencies
|
||||||
|
Write-Warn "Контейнеры будут удалены. Тома с данными сохранятся."
|
||||||
|
$confirm = Read-Host "Продолжить? [y/N]"
|
||||||
|
if ($confirm -notmatch '^[Yy]$') {
|
||||||
|
Write-Info "Отменено."
|
||||||
|
return
|
||||||
|
}
|
||||||
|
docker compose down
|
||||||
|
Write-Info "Контейнеры удалены. Для полного удаления данных: docker volume rm gitea_gitea_data gitea_postgres_data"
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
switch ($Command) {
|
||||||
|
"install" { Invoke-Install }
|
||||||
|
"start" { Invoke-Start }
|
||||||
|
"stop" { Invoke-Stop }
|
||||||
|
"restart" { Invoke-Restart }
|
||||||
|
"update" { Invoke-Update }
|
||||||
|
"status" { Invoke-Status }
|
||||||
|
"logs" { Invoke-Logs }
|
||||||
|
"backup" { Invoke-Backup }
|
||||||
|
"restore" { Invoke-Restore }
|
||||||
|
"uninstall" { Invoke-Uninstall }
|
||||||
|
"help" { Show-Usage }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
202
deploy.sh
Normal file
202
deploy.sh
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source "${SCRIPT_DIR}/lib/common.sh"
|
||||||
|
|
||||||
|
NON_INTERACTIVE=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Использование: ./deploy.sh [команда] [опции]
|
||||||
|
|
||||||
|
Команды:
|
||||||
|
install — первичное развертывание (по умолчанию)
|
||||||
|
start — запуск контейнеров
|
||||||
|
stop — остановка контейнеров
|
||||||
|
restart — перезапуск
|
||||||
|
update — обновление образов и перезапуск
|
||||||
|
status — статус контейнеров
|
||||||
|
logs — просмотр логов Gitea
|
||||||
|
backup — резервная копия данных
|
||||||
|
restore — восстановление из backup (./deploy.sh restore <файл.tar.gz>)
|
||||||
|
uninstall — остановка и удаление контейнеров (данные сохраняются)
|
||||||
|
|
||||||
|
Опции install:
|
||||||
|
-y, --yes Без интерактивных вопросов (значения из .env.example, пароль — автогенерация)
|
||||||
|
|
||||||
|
Примеры:
|
||||||
|
./deploy.sh install
|
||||||
|
./deploy.sh install -y
|
||||||
|
./deploy.sh update
|
||||||
|
./deploy.sh backup
|
||||||
|
./deploy.sh restore backups/gitea-backup-20260101.tar.gz
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_install() {
|
||||||
|
log "Проверка зависимостей..."
|
||||||
|
check_dependencies
|
||||||
|
setup_env_interactive "$NON_INTERACTIVE"
|
||||||
|
|
||||||
|
log "Загрузка образов..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
log "Запуск Gitea..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
log "Ожидание готовности сервисов..."
|
||||||
|
sleep 5
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
log "Gitea развернута!"
|
||||||
|
log " Web: http://${GITEA_DOMAIN:-localhost}:${GITEA_HTTP_PORT:-3000}"
|
||||||
|
log " SSH: ssh://git@${GITEA_DOMAIN:-localhost}:${GITEA_SSH_PORT:-2222}"
|
||||||
|
log "При первом входе откройте Web UI и завершите мастер настройки."
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_start() {
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_stop() {
|
||||||
|
check_dependencies
|
||||||
|
docker compose down
|
||||||
|
log "Контейнеры остановлены."
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_restart() {
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
docker compose restart
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_update() {
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
log "Обновление образов..."
|
||||||
|
docker compose pull
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
log "Обновление завершено."
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_status() {
|
||||||
|
check_dependencies
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_logs() {
|
||||||
|
check_dependencies
|
||||||
|
docker compose logs -f --tail=100 gitea
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_backup() {
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
|
||||||
|
BACKUP_DIR="${SCRIPT_DIR}/backups"
|
||||||
|
TIMESTAMP="$(date +%Y%m%d-%H%M%S)"
|
||||||
|
BACKUP_FILE="${BACKUP_DIR}/gitea-backup-${TIMESTAMP}.tar.gz"
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
log "Создание резервной копии: $BACKUP_FILE"
|
||||||
|
|
||||||
|
docker compose exec -T db pg_dump -U "${POSTGRES_USER:-gitea}" "${POSTGRES_DB:-gitea}" \
|
||||||
|
> "${BACKUP_DIR}/gitea-db-${TIMESTAMP}.sql"
|
||||||
|
|
||||||
|
docker run --rm \
|
||||||
|
-v gitea_gitea_data:/gitea_data:ro \
|
||||||
|
-v gitea_postgres_data:/postgres_data:ro \
|
||||||
|
-v "${BACKUP_DIR}:/backup" \
|
||||||
|
alpine:3.20 \
|
||||||
|
sh -c "tar czf /backup/gitea-backup-${TIMESTAMP}.tar.gz -C / gitea_data postgres_data && rm -f /backup/gitea-db-${TIMESTAMP}.sql"
|
||||||
|
|
||||||
|
log "Резервная копия сохранена: $BACKUP_FILE"
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_restore() {
|
||||||
|
local backup_file="${1:-}"
|
||||||
|
|
||||||
|
if [[ -z "$backup_file" || ! -f "$backup_file" ]]; then
|
||||||
|
err "Укажите существующий файл резервной копии."
|
||||||
|
err "Пример: ./deploy.sh restore backups/gitea-backup-20260101.tar.gz"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
|
||||||
|
warn "Восстановление перезапишет текущие данные!"
|
||||||
|
read -r -p "Продолжить? [y/N] " confirm
|
||||||
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
log "Отменено."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Остановка контейнеров..."
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
log "Восстановление из $backup_file..."
|
||||||
|
docker run --rm \
|
||||||
|
-v gitea_gitea_data:/gitea_data \
|
||||||
|
-v gitea_postgres_data:/postgres_data \
|
||||||
|
-v "$(dirname "$(realpath "$backup_file")"):/backup:ro" \
|
||||||
|
alpine:3.20 \
|
||||||
|
sh -c "cd / && tar xzf /backup/$(basename "$backup_file")"
|
||||||
|
|
||||||
|
log "Запуск контейнеров..."
|
||||||
|
docker compose up -d
|
||||||
|
log "Восстановление завершено."
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_uninstall() {
|
||||||
|
check_dependencies
|
||||||
|
warn "Контейнеры будут удалены. Тома с данными сохранятся."
|
||||||
|
read -r -p "Продолжить? [y/N] " confirm
|
||||||
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
log "Отменено."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
docker compose down
|
||||||
|
log "Контейнеры удалены. Для полного удаления данных: docker volume rm gitea_gitea_data gitea_postgres_data"
|
||||||
|
}
|
||||||
|
|
||||||
|
COMMAND="${1:-install}"
|
||||||
|
shift $(( $# > 0 ? 1 : 0 )) || true
|
||||||
|
|
||||||
|
if [[ "$COMMAND" == "install" ]]; then
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
-y|--yes) NON_INTERACTIVE=true; shift ;;
|
||||||
|
-h|--help|help) usage; exit 0 ;;
|
||||||
|
*) err "Неизвестная опция: $1"; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
case "$COMMAND" in
|
||||||
|
install) cmd_install ;;
|
||||||
|
start) cmd_start ;;
|
||||||
|
stop) cmd_stop ;;
|
||||||
|
restart) cmd_restart ;;
|
||||||
|
update) cmd_update ;;
|
||||||
|
status) cmd_status ;;
|
||||||
|
logs) cmd_logs ;;
|
||||||
|
backup) cmd_backup ;;
|
||||||
|
restore) cmd_restore "${1:-}" ;;
|
||||||
|
uninstall) cmd_uninstall ;;
|
||||||
|
-h|--help|help) usage ;;
|
||||||
|
*)
|
||||||
|
err "Неизвестная команда: $COMMAND"
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
57
docker-compose.yml
Normal file
57
docker-compose.yml
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
services:
|
||||||
|
db:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
container_name: gitea-db
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${POSTGRES_USER:-gitea}
|
||||||
|
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}
|
||||||
|
POSTGRES_DB: ${POSTGRES_DB:-gitea}
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-gitea} -d ${POSTGRES_DB:-gitea}"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
|
||||||
|
gitea:
|
||||||
|
image: gitea/gitea:${GITEA_VERSION:-1.22.6}
|
||||||
|
container_name: gitea
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
db:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
USER_UID: 1000
|
||||||
|
USER_GID: 1000
|
||||||
|
TZ: ${TZ:-UTC}
|
||||||
|
GITEA__database__DB_TYPE: postgres
|
||||||
|
GITEA__database__HOST: db:5432
|
||||||
|
GITEA__database__NAME: ${POSTGRES_DB:-gitea}
|
||||||
|
GITEA__database__USER: ${POSTGRES_USER:-gitea}
|
||||||
|
GITEA__database__PASSWD: ${POSTGRES_PASSWORD}
|
||||||
|
GITEA__server__DOMAIN: ${GITEA_DOMAIN:-localhost}
|
||||||
|
GITEA__server__ROOT_URL: http://${GITEA_DOMAIN:-localhost}:${GITEA_HTTP_PORT:-3000}/
|
||||||
|
GITEA__server__SSH_DOMAIN: ${GITEA_DOMAIN:-localhost}
|
||||||
|
GITEA__server__SSH_PORT: ${GITEA_SSH_PORT:-2222}
|
||||||
|
GITEA__server__SSH_LISTEN_PORT: 22
|
||||||
|
GITEA__server__LFS_START_SERVER: "true"
|
||||||
|
ports:
|
||||||
|
- "${GITEA_HTTP_PORT:-3000}:3000"
|
||||||
|
- "${GITEA_SSH_PORT:-2222}:22"
|
||||||
|
volumes:
|
||||||
|
- gitea_data:/data
|
||||||
|
networks:
|
||||||
|
- gitea
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
gitea_data:
|
||||||
|
|
||||||
|
networks:
|
||||||
|
gitea:
|
||||||
|
driver: bridge
|
||||||
71
install-service.ps1
Normal file
71
install-service.ps1
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
#Requires -RunAsAdministrator
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$TaskName = "Gitea"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Test-Dependencies
|
||||||
|
|
||||||
|
if (-not (Test-Path ".env")) {
|
||||||
|
throw "Файл .env не найден. Сначала выполните .\deploy.ps1 install"
|
||||||
|
}
|
||||||
|
|
||||||
|
$startScript = Join-Path $script:ScriptDir "start.ps1"
|
||||||
|
$stopScript = Join-Path $script:ScriptDir "stop.ps1"
|
||||||
|
|
||||||
|
$existing = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||||
|
if ($existing) {
|
||||||
|
Write-Warn "Задача '$TaskName' уже существует. Перерегистрация..."
|
||||||
|
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Info "Регистрация задачи автозапуска: $TaskName"
|
||||||
|
|
||||||
|
$startAction = New-ScheduledTaskAction `
|
||||||
|
-Execute "powershell.exe" `
|
||||||
|
-Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$startScript`""
|
||||||
|
|
||||||
|
$stopAction = New-ScheduledTaskAction `
|
||||||
|
-Execute "powershell.exe" `
|
||||||
|
-Argument "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File `"$stopScript`""
|
||||||
|
|
||||||
|
$startupTrigger = New-ScheduledTaskTrigger -AtStartup
|
||||||
|
$startupTrigger.Delay = "PT1M"
|
||||||
|
|
||||||
|
$principal = New-ScheduledTaskPrincipal `
|
||||||
|
-UserId "SYSTEM" `
|
||||||
|
-LogonType ServiceAccount `
|
||||||
|
-RunLevel Highest
|
||||||
|
|
||||||
|
$settings = New-ScheduledTaskSettingsSet `
|
||||||
|
-AllowStartIfOnBatteries `
|
||||||
|
-DontStopIfGoingOnBatteries `
|
||||||
|
-StartWhenAvailable `
|
||||||
|
-ExecutionTimeLimit ([TimeSpan]::Zero)
|
||||||
|
|
||||||
|
Register-ScheduledTask `
|
||||||
|
-TaskName $TaskName `
|
||||||
|
-Action $startAction `
|
||||||
|
-Trigger $startupTrigger `
|
||||||
|
-Principal $principal `
|
||||||
|
-Settings $settings `
|
||||||
|
-Description "Автозапуск Gitea (Docker Compose)" | Out-Null
|
||||||
|
|
||||||
|
Write-Info "Запуск Gitea..."
|
||||||
|
& $startScript
|
||||||
|
|
||||||
|
Write-Info "Задача '$TaskName' установлена. Gitea будет запускаться при загрузке Windows."
|
||||||
|
Write-Info "Управление:"
|
||||||
|
Write-Info " Start-ScheduledTask -TaskName $TaskName"
|
||||||
|
Write-Info " Stop-ScheduledTask -TaskName $TaskName"
|
||||||
|
Write-Info " Get-ScheduledTask -TaskName $TaskName"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
60
install-service.sh
Normal file
60
install-service.sh
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
|
||||||
|
SERVICE_NAME="gitea"
|
||||||
|
UNIT_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
TEMPLATE_FILE="${SCRIPT_DIR}/systemd/gitea.service"
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Использование: sudo ./install-service.sh
|
||||||
|
|
||||||
|
Регистрирует systemd-службу для автозапуска Gitea при загрузке системы.
|
||||||
|
|
||||||
|
Управление после установки:
|
||||||
|
sudo systemctl start gitea
|
||||||
|
sudo systemctl stop gitea
|
||||||
|
sudo systemctl status gitea
|
||||||
|
sudo systemctl enable gitea
|
||||||
|
sudo systemctl disable gitea
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||||
|
err "Запустите скрипт от root: sudo ./install-service.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$TEMPLATE_FILE" ]]; then
|
||||||
|
err "Не найден шаблон: $TEMPLATE_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
check_dependencies
|
||||||
|
|
||||||
|
if [[ ! -f "${SCRIPT_DIR}/.env" ]]; then
|
||||||
|
err "Файл .env не найден. Сначала выполните ./deploy.sh install"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Создание unit-файла: $UNIT_FILE"
|
||||||
|
sed "s|__GITEA_DIR__|${SCRIPT_DIR}|g" "$TEMPLATE_FILE" > "$UNIT_FILE"
|
||||||
|
|
||||||
|
log "Перезагрузка systemd..."
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
log "Включение автозапуска..."
|
||||||
|
systemctl enable "$SERVICE_NAME"
|
||||||
|
|
||||||
|
if docker compose ps --status running -q 2>/dev/null | grep -q .; then
|
||||||
|
log "Контейнеры уже запущены."
|
||||||
|
else
|
||||||
|
log "Запуск службы..."
|
||||||
|
systemctl start "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl status "$SERVICE_NAME" --no-pager || true
|
||||||
|
log "Служба ${SERVICE_NAME} установлена и включена в автозагрузку."
|
||||||
207
lib/common.ps1
Normal file
207
lib/common.ps1
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
function Write-Info($Message) { Write-Host "[INFO] $Message" -ForegroundColor Green }
|
||||||
|
function Write-Warn($Message) { Write-Host "[WARN] $Message" -ForegroundColor Yellow }
|
||||||
|
function Write-Err($Message) { Write-Host "[ERROR] $Message" -ForegroundColor Red }
|
||||||
|
|
||||||
|
function Test-Dependencies {
|
||||||
|
if (-not (Get-Command docker -ErrorAction SilentlyContinue)) {
|
||||||
|
throw "Docker не найден. Установите Docker Desktop."
|
||||||
|
}
|
||||||
|
|
||||||
|
docker compose version 2>$null | Out-Null
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "Docker Compose v2 не найден."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Import-EnvFromFile {
|
||||||
|
param([string]$Path)
|
||||||
|
|
||||||
|
if (-not (Test-Path $Path)) { return }
|
||||||
|
|
||||||
|
Get-Content $Path | ForEach-Object {
|
||||||
|
if ($_ -match '^\s*#' -or $_ -match '^\s*$') { return }
|
||||||
|
$parts = $_ -split '=', 2
|
||||||
|
if ($parts.Count -eq 2) {
|
||||||
|
$name = $parts[0].Trim()
|
||||||
|
$value = $parts[1].Trim()
|
||||||
|
Set-Item -Path "env:$name" -Value $value -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function New-RandomPassword {
|
||||||
|
param([int]$Length = 20)
|
||||||
|
$bytes = New-Object byte[] 32
|
||||||
|
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes)
|
||||||
|
$token = [Convert]::ToBase64String($bytes) -replace '[^A-Za-z0-9]', ''
|
||||||
|
if ($token.Length -ge $Length) {
|
||||||
|
return $token.Substring(0, $Length)
|
||||||
|
}
|
||||||
|
return ($token + ('A' * $Length)).Substring(0, $Length)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Read-PromptValue {
|
||||||
|
param(
|
||||||
|
[string]$Prompt,
|
||||||
|
[string]$Default,
|
||||||
|
[switch]$Secret
|
||||||
|
)
|
||||||
|
|
||||||
|
if ($Secret) {
|
||||||
|
Write-Host "$Prompt (Enter — автогенерация): " -NoNewline
|
||||||
|
$secure = Read-Host -AsSecureString
|
||||||
|
$input = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
|
||||||
|
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
|
||||||
|
)
|
||||||
|
if ([string]::IsNullOrWhiteSpace($input)) {
|
||||||
|
$input = New-RandomPassword
|
||||||
|
Write-Warn "Сгенерирован пароль PostgreSQL: $input"
|
||||||
|
}
|
||||||
|
return $input
|
||||||
|
}
|
||||||
|
|
||||||
|
$input = Read-Host "$Prompt [$Default]"
|
||||||
|
if ([string]::IsNullOrWhiteSpace($input)) {
|
||||||
|
return $Default
|
||||||
|
}
|
||||||
|
return $input
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-EnvFile {
|
||||||
|
$content = @"
|
||||||
|
# Сгенерировано $(Get-Date -Format "yyyy-MM-ddTHH:mm:ss")
|
||||||
|
|
||||||
|
# Домен или IP сервера (без http/https)
|
||||||
|
GITEA_DOMAIN=$($env:GITEA_DOMAIN)
|
||||||
|
|
||||||
|
# Порт веб-интерфейса Gitea
|
||||||
|
GITEA_HTTP_PORT=$($env:GITEA_HTTP_PORT)
|
||||||
|
|
||||||
|
# Порт SSH для git clone/push
|
||||||
|
GITEA_SSH_PORT=$($env:GITEA_SSH_PORT)
|
||||||
|
|
||||||
|
# Версия образа Gitea
|
||||||
|
GITEA_VERSION=$($env:GITEA_VERSION)
|
||||||
|
|
||||||
|
# База данных PostgreSQL
|
||||||
|
POSTGRES_USER=$($env:POSTGRES_USER)
|
||||||
|
POSTGRES_PASSWORD=$($env:POSTGRES_PASSWORD)
|
||||||
|
POSTGRES_DB=$($env:POSTGRES_DB)
|
||||||
|
|
||||||
|
# Часовой пояс
|
||||||
|
TZ=$($env:TZ)
|
||||||
|
"@
|
||||||
|
|
||||||
|
$path = Join-Path $script:ScriptDir ".env"
|
||||||
|
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
|
||||||
|
[System.IO.File]::WriteAllText($path, $content + "`n", $utf8NoBom)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Initialize-EnvDefaults {
|
||||||
|
param([string]$DefaultsFile)
|
||||||
|
|
||||||
|
Import-EnvFromFile $DefaultsFile
|
||||||
|
|
||||||
|
if (-not $env:GITEA_DOMAIN) { $env:GITEA_DOMAIN = "localhost" }
|
||||||
|
if (-not $env:GITEA_HTTP_PORT) { $env:GITEA_HTTP_PORT = "3000" }
|
||||||
|
if (-not $env:GITEA_SSH_PORT) { $env:GITEA_SSH_PORT = "2222" }
|
||||||
|
if (-not $env:GITEA_VERSION) { $env:GITEA_VERSION = "1.22.6" }
|
||||||
|
if (-not $env:POSTGRES_USER) { $env:POSTGRES_USER = "gitea" }
|
||||||
|
if (-not $env:POSTGRES_DB) { $env:POSTGRES_DB = "gitea" }
|
||||||
|
if (-not $env:TZ) { $env:TZ = "Europe/Moscow" }
|
||||||
|
}
|
||||||
|
|
||||||
|
function Invoke-SetupEnvInteractive {
|
||||||
|
param([switch]$NonInteractive)
|
||||||
|
|
||||||
|
$defaultsFile = ".env.example"
|
||||||
|
|
||||||
|
if (Test-Path ".env") {
|
||||||
|
$defaultsFile = ".env"
|
||||||
|
if (-not $NonInteractive) {
|
||||||
|
Write-Warn "Файл .env уже существует."
|
||||||
|
$confirm = Read-Host "Пересоздать конфигурацию? [y/N]"
|
||||||
|
if ($confirm -notmatch '^[Yy]$') {
|
||||||
|
Import-EnvFromFile ".env"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $defaultsFile) -and -not (Test-Path ".env.example")) {
|
||||||
|
throw "Не найден .env.example"
|
||||||
|
}
|
||||||
|
|
||||||
|
if (-not (Test-Path $defaultsFile)) {
|
||||||
|
$defaultsFile = ".env.example"
|
||||||
|
}
|
||||||
|
|
||||||
|
Remove-Item Env:GITEA_DOMAIN, Env:GITEA_HTTP_PORT, Env:GITEA_SSH_PORT, Env:GITEA_VERSION -ErrorAction SilentlyContinue
|
||||||
|
Remove-Item Env:POSTGRES_USER, Env:POSTGRES_PASSWORD, Env:POSTGRES_DB, Env:TZ -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
Initialize-EnvDefaults $defaultsFile
|
||||||
|
|
||||||
|
if ($NonInteractive) {
|
||||||
|
if ([string]::IsNullOrWhiteSpace($env:POSTGRES_PASSWORD) -or $env:POSTGRES_PASSWORD -eq "change_me_strong_password") {
|
||||||
|
$env:POSTGRES_PASSWORD = New-RandomPassword
|
||||||
|
Write-Warn "Сгенерирован пароль PostgreSQL: $($env:POSTGRES_PASSWORD)"
|
||||||
|
}
|
||||||
|
Write-EnvFile
|
||||||
|
Import-EnvFromFile ".env"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "=== Настройка Gitea ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Enter — оставить значение в скобках."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$env:GITEA_DOMAIN = Read-PromptValue "Домен или IP сервера" $env:GITEA_DOMAIN
|
||||||
|
$env:GITEA_HTTP_PORT = Read-PromptValue "Порт веб-интерфейса" $env:GITEA_HTTP_PORT
|
||||||
|
$env:GITEA_SSH_PORT = Read-PromptValue "Порт SSH для Git" $env:GITEA_SSH_PORT
|
||||||
|
$env:GITEA_VERSION = Read-PromptValue "Версия образа Gitea" $env:GITEA_VERSION
|
||||||
|
$env:POSTGRES_USER = Read-PromptValue "Пользователь PostgreSQL" $env:POSTGRES_USER
|
||||||
|
$env:POSTGRES_DB = Read-PromptValue "Имя базы данных" $env:POSTGRES_DB
|
||||||
|
$env:TZ = Read-PromptValue "Часовой пояс (TZ)" $env:TZ
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
$env:POSTGRES_PASSWORD = Read-PromptValue "Пароль PostgreSQL" "" -Secret
|
||||||
|
|
||||||
|
Write-EnvFile
|
||||||
|
Import-EnvFromFile ".env"
|
||||||
|
Write-Info "Конфигурация сохранена в .env"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Import-EnvFile {
|
||||||
|
if (-not (Test-Path ".env")) {
|
||||||
|
throw "Файл .env не найден. Выполните: .\deploy.ps1 install"
|
||||||
|
}
|
||||||
|
|
||||||
|
Import-EnvFromFile ".env"
|
||||||
|
|
||||||
|
if ($env:POSTGRES_PASSWORD -eq "change_me_strong_password") {
|
||||||
|
Write-Warn "Используется пароль по умолчанию! Измените POSTGRES_PASSWORD в .env"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Confirm-OrExit {
|
||||||
|
param([string]$Message = "Продолжить?")
|
||||||
|
$confirm = Read-Host "$Message [y/N]"
|
||||||
|
if ($confirm -notmatch '^[Yy]$') {
|
||||||
|
Write-Info "Отменено."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-ComposeProjectName {
|
||||||
|
if ($env:COMPOSE_PROJECT_NAME) {
|
||||||
|
return $env:COMPOSE_PROJECT_NAME
|
||||||
|
}
|
||||||
|
$name = Split-Path $script:ScriptDir -Leaf
|
||||||
|
return ($name.ToLower() -replace '[^a-z0-9_-]', '_')
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-VolumeNames {
|
||||||
|
$prefix = Get-ComposeProjectName
|
||||||
|
return @("${prefix}_gitea_data", "${prefix}_postgres_data")
|
||||||
|
}
|
||||||
199
lib/common.sh
Normal file
199
lib/common.sh
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
CYAN='\033[0;36m'
|
||||||
|
NC='\033[0m'
|
||||||
|
|
||||||
|
log() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||||
|
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||||
|
err() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||||
|
|
||||||
|
init_script_dir() {
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[1]}")" && pwd)"
|
||||||
|
cd "$SCRIPT_DIR"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_dependencies() {
|
||||||
|
if ! command -v docker >/dev/null 2>&1; then
|
||||||
|
err "Не найдена команда: docker"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! docker compose version >/dev/null 2>&1; then
|
||||||
|
err "Docker Compose v2 не найден. Установите docker compose plugin."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
load_env_from_file() {
|
||||||
|
local file="$1"
|
||||||
|
[[ -f "$file" ]] || return 0
|
||||||
|
|
||||||
|
while IFS= read -r line || [[ -n "$line" ]]; do
|
||||||
|
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
||||||
|
[[ -z "${line// }" ]] && continue
|
||||||
|
if [[ "$line" =~ ^([A-Za-z_][A-Za-z0-9_]*)=(.*)$ ]]; then
|
||||||
|
export "${BASH_REMATCH[1]}=${BASH_REMATCH[2]}"
|
||||||
|
fi
|
||||||
|
done < "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
generate_password() {
|
||||||
|
if command -v openssl >/dev/null 2>&1; then
|
||||||
|
openssl rand -base64 24 | tr -dc 'A-Za-z0-9' | head -c 20
|
||||||
|
else
|
||||||
|
tr -dc 'A-Za-z0-9' </dev/urandom 2>/dev/null | head -c 20
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
prompt_value() {
|
||||||
|
local prompt_text="$1"
|
||||||
|
local default_value="$2"
|
||||||
|
local secret="${3:-false}"
|
||||||
|
local input=""
|
||||||
|
|
||||||
|
if [[ "$secret" == true ]]; then
|
||||||
|
read -rs -p "$prompt_text (Enter — автогенерация): " input
|
||||||
|
echo
|
||||||
|
if [[ -z "$input" ]]; then
|
||||||
|
input="$(generate_password)"
|
||||||
|
warn "Сгенерирован пароль PostgreSQL: $input"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
read -r -p "$prompt_text [$default_value]: " input
|
||||||
|
if [[ -z "$input" ]]; then
|
||||||
|
input="$default_value"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s' "$input"
|
||||||
|
}
|
||||||
|
|
||||||
|
write_env_file() {
|
||||||
|
cat > .env <<EOF
|
||||||
|
# Сгенерировано $(date -Iseconds 2>/dev/null || date)
|
||||||
|
|
||||||
|
# Домен или IP сервера (без http/https)
|
||||||
|
GITEA_DOMAIN=${GITEA_DOMAIN}
|
||||||
|
|
||||||
|
# Порт веб-интерфейса Gitea
|
||||||
|
GITEA_HTTP_PORT=${GITEA_HTTP_PORT}
|
||||||
|
|
||||||
|
# Порт SSH для git clone/push
|
||||||
|
GITEA_SSH_PORT=${GITEA_SSH_PORT}
|
||||||
|
|
||||||
|
# Версия образа Gitea
|
||||||
|
GITEA_VERSION=${GITEA_VERSION}
|
||||||
|
|
||||||
|
# База данных PostgreSQL
|
||||||
|
POSTGRES_USER=${POSTGRES_USER}
|
||||||
|
POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
|
||||||
|
POSTGRES_DB=${POSTGRES_DB}
|
||||||
|
|
||||||
|
# Часовой пояс
|
||||||
|
TZ=${TZ}
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
setup_env_interactive() {
|
||||||
|
local non_interactive="${1:-false}"
|
||||||
|
local defaults_file=".env.example"
|
||||||
|
|
||||||
|
if [[ -f .env ]]; then
|
||||||
|
defaults_file=".env"
|
||||||
|
if [[ "$non_interactive" != true ]]; then
|
||||||
|
warn "Файл .env уже существует."
|
||||||
|
read -r -p "Пересоздать конфигурацию? [y/N] " confirm
|
||||||
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
load_env_from_file .env
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$defaults_file" && ! -f .env.example ]]; then
|
||||||
|
err "Не найден .env.example"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[[ -f "$defaults_file" ]] || defaults_file=".env.example"
|
||||||
|
|
||||||
|
unset GITEA_DOMAIN GITEA_HTTP_PORT GITEA_SSH_PORT GITEA_VERSION
|
||||||
|
unset POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DB TZ
|
||||||
|
load_env_from_file "$defaults_file"
|
||||||
|
|
||||||
|
GITEA_DOMAIN="${GITEA_DOMAIN:-localhost}"
|
||||||
|
GITEA_HTTP_PORT="${GITEA_HTTP_PORT:-3000}"
|
||||||
|
GITEA_SSH_PORT="${GITEA_SSH_PORT:-2222}"
|
||||||
|
GITEA_VERSION="${GITEA_VERSION:-1.22.6}"
|
||||||
|
POSTGRES_USER="${POSTGRES_USER:-gitea}"
|
||||||
|
POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-}"
|
||||||
|
POSTGRES_DB="${POSTGRES_DB:-gitea}"
|
||||||
|
TZ="${TZ:-Europe/Moscow}"
|
||||||
|
|
||||||
|
if [[ "$non_interactive" == true ]]; then
|
||||||
|
if [[ -z "$POSTGRES_PASSWORD" || "$POSTGRES_PASSWORD" == "change_me_strong_password" ]]; then
|
||||||
|
POSTGRES_PASSWORD="$(generate_password)"
|
||||||
|
warn "Сгенерирован пароль PostgreSQL: $POSTGRES_PASSWORD"
|
||||||
|
fi
|
||||||
|
write_env_file
|
||||||
|
load_env_from_file .env
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo -e "${CYAN}=== Настройка Gitea ===${NC}"
|
||||||
|
echo "Enter — оставить значение в скобках."
|
||||||
|
echo
|
||||||
|
|
||||||
|
GITEA_DOMAIN="$(prompt_value "Домен или IP сервера" "$GITEA_DOMAIN")"
|
||||||
|
GITEA_HTTP_PORT="$(prompt_value "Порт веб-интерфейса" "$GITEA_HTTP_PORT")"
|
||||||
|
GITEA_SSH_PORT="$(prompt_value "Порт SSH для Git" "$GITEA_SSH_PORT")"
|
||||||
|
GITEA_VERSION="$(prompt_value "Версия образа Gitea" "$GITEA_VERSION")"
|
||||||
|
POSTGRES_USER="$(prompt_value "Пользователь PostgreSQL" "$POSTGRES_USER")"
|
||||||
|
POSTGRES_DB="$(prompt_value "Имя базы данных" "$POSTGRES_DB")"
|
||||||
|
TZ="$(prompt_value "Часовой пояс (TZ)" "$TZ")"
|
||||||
|
|
||||||
|
echo
|
||||||
|
POSTGRES_PASSWORD="$(prompt_value "Пароль PostgreSQL" "" true)"
|
||||||
|
|
||||||
|
write_env_file
|
||||||
|
load_env_from_file .env
|
||||||
|
log "Конфигурация сохранена в .env"
|
||||||
|
}
|
||||||
|
|
||||||
|
ensure_env() {
|
||||||
|
if [[ ! -f .env ]]; then
|
||||||
|
err "Файл .env не найден. Выполните: ./deploy.sh install"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
load_env_from_file .env
|
||||||
|
|
||||||
|
if [[ "${POSTGRES_PASSWORD:-}" == "change_me_strong_password" ]]; then
|
||||||
|
warn "Используется пароль по умолчанию! Измените POSTGRES_PASSWORD в .env"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
confirm_or_exit() {
|
||||||
|
local message="${1:-Продолжить?}"
|
||||||
|
read -r -p "$message [y/N] " confirm
|
||||||
|
if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
|
||||||
|
log "Отменено."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
get_compose_project_name() {
|
||||||
|
local project_name
|
||||||
|
project_name="$(basename "$SCRIPT_DIR" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9_-]/_/g')"
|
||||||
|
echo "${COMPOSE_PROJECT_NAME:-$project_name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
get_volume_names() {
|
||||||
|
local prefix
|
||||||
|
prefix="$(get_compose_project_name)"
|
||||||
|
echo "${prefix}_gitea_data ${prefix}_postgres_data"
|
||||||
|
}
|
||||||
55
reinstall.ps1
Normal file
55
reinstall.ps1
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
|
||||||
|
param(
|
||||||
|
[switch]$Purge
|
||||||
|
)
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Test-Dependencies
|
||||||
|
|
||||||
|
if ($Purge) {
|
||||||
|
Write-Warn "Данные будут удалены. Gitea будет установлена заново."
|
||||||
|
Confirm-OrExit "Продолжить?"
|
||||||
|
|
||||||
|
docker compose down -v 2>$null
|
||||||
|
if ($LASTEXITCODE -ne 0) { docker compose down }
|
||||||
|
|
||||||
|
foreach ($vol in Get-VolumeNames) {
|
||||||
|
docker volume rm $vol 2>$null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Warn "Контейнеры будут пересозданы. Данные сохранятся."
|
||||||
|
Confirm-OrExit "Продолжить?"
|
||||||
|
docker compose down
|
||||||
|
}
|
||||||
|
|
||||||
|
Import-EnvFile
|
||||||
|
|
||||||
|
Write-Info "Загрузка образов..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
Write-Info "Запуск Gitea..."
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
$domain = if ($env:GITEA_DOMAIN) { $env:GITEA_DOMAIN } else { "localhost" }
|
||||||
|
$httpPort = if ($env:GITEA_HTTP_PORT) { $env:GITEA_HTTP_PORT } else { "3000" }
|
||||||
|
$sshPort = if ($env:GITEA_SSH_PORT) { $env:GITEA_SSH_PORT } else { "2222" }
|
||||||
|
|
||||||
|
Write-Info "Переустановка завершена."
|
||||||
|
Write-Info " Web: http://${domain}:${httpPort}"
|
||||||
|
Write-Info " SSH: ssh://git@${domain}:${sshPort}"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
57
reinstall.sh
Normal file
57
reinstall.sh
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
check_dependencies
|
||||||
|
|
||||||
|
PURGE=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Использование: ./reinstall.sh [--purge]
|
||||||
|
|
||||||
|
Переустановка: остановка, обновление образов, повторный запуск.
|
||||||
|
|
||||||
|
--purge Удалить данные перед переустановкой (чистая установка)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--purge) PURGE=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) err "Неизвестный аргумент: $1"; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$PURGE" == true ]]; then
|
||||||
|
warn "Данные будут удалены. Gitea будет установлена заново."
|
||||||
|
confirm_or_exit "Продолжить?"
|
||||||
|
docker compose down -v 2>/dev/null || docker compose down
|
||||||
|
read -r -a volumes <<< "$(get_volume_names)"
|
||||||
|
for vol in "${volumes[@]}"; do
|
||||||
|
docker volume rm "$vol" 2>/dev/null || true
|
||||||
|
done
|
||||||
|
else
|
||||||
|
warn "Контейнеры будут пересозданы. Данные сохранятся."
|
||||||
|
confirm_or_exit "Продолжить?"
|
||||||
|
docker compose down
|
||||||
|
fi
|
||||||
|
|
||||||
|
ensure_env
|
||||||
|
|
||||||
|
log "Загрузка образов..."
|
||||||
|
docker compose pull
|
||||||
|
|
||||||
|
log "Запуск Gitea..."
|
||||||
|
docker compose up -d --force-recreate
|
||||||
|
|
||||||
|
sleep 5
|
||||||
|
docker compose ps
|
||||||
|
|
||||||
|
# shellcheck disable=SC1091
|
||||||
|
source .env
|
||||||
|
log "Переустановка завершена."
|
||||||
|
log " Web: http://${GITEA_DOMAIN:-localhost}:${GITEA_HTTP_PORT:-3000}"
|
||||||
|
log " SSH: ssh://git@${GITEA_DOMAIN:-localhost}:${GITEA_SSH_PORT:-2222}"
|
||||||
32
remove-service.ps1
Normal file
32
remove-service.ps1
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
#Requires -RunAsAdministrator
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
$TaskName = "Gitea"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$task = Get-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||||
|
if (-not $task) {
|
||||||
|
Write-Warn "Задача '$TaskName' не найдена."
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Warn "Задача '$TaskName' будет удалена из планировщика."
|
||||||
|
Confirm-OrExit "Продолжить?"
|
||||||
|
|
||||||
|
if ((Get-ScheduledTask -TaskName $TaskName).State -eq "Running") {
|
||||||
|
Write-Info "Остановка задачи..."
|
||||||
|
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false
|
||||||
|
Write-Info "Задача '$TaskName' удалена. Контейнеры и данные не затронуты."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
37
remove-service.sh
Normal file
37
remove-service.sh
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
|
||||||
|
SERVICE_NAME="gitea"
|
||||||
|
UNIT_FILE="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||||
|
|
||||||
|
if [[ "${EUID:-$(id -u)}" -ne 0 ]]; then
|
||||||
|
err "Запустите скрипт от root: sudo ./remove-service.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -f "$UNIT_FILE" ]]; then
|
||||||
|
warn "Служба ${SERVICE_NAME} не установлена."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
warn "Служба ${SERVICE_NAME} будет остановлена и удалена из автозагрузки."
|
||||||
|
confirm_or_exit "Продолжить?"
|
||||||
|
|
||||||
|
if systemctl is-active --quiet "$SERVICE_NAME"; then
|
||||||
|
log "Остановка службы..."
|
||||||
|
systemctl stop "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
|
||||||
|
log "Отключение автозапуска..."
|
||||||
|
systemctl disable "$SERVICE_NAME"
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Удаление unit-файла..."
|
||||||
|
rm -f "$UNIT_FILE"
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
log "Служба ${SERVICE_NAME} удалена. Контейнеры и данные не затронуты."
|
||||||
20
start.ps1
Normal file
20
start.ps1
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Test-Dependencies
|
||||||
|
Import-EnvFile
|
||||||
|
|
||||||
|
Write-Info "Запуск Gitea..."
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
11
start.sh
Normal file
11
start.sh
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
check_dependencies
|
||||||
|
ensure_env
|
||||||
|
|
||||||
|
log "Запуск Gitea..."
|
||||||
|
docker compose up -d
|
||||||
|
docker compose ps
|
||||||
19
stop.ps1
Normal file
19
stop.ps1
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Test-Dependencies
|
||||||
|
|
||||||
|
Write-Info "Остановка Gitea..."
|
||||||
|
docker compose down
|
||||||
|
Write-Info "Контейнеры остановлены."
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
10
stop.sh
Normal file
10
stop.sh
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
check_dependencies
|
||||||
|
|
||||||
|
log "Остановка Gitea..."
|
||||||
|
docker compose down
|
||||||
|
log "Контейнеры остановлены."
|
||||||
17
systemd/gitea.service
Normal file
17
systemd/gitea.service
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Gitea (Docker Compose)
|
||||||
|
Documentation=https://about.gitea.com/
|
||||||
|
Requires=docker.service
|
||||||
|
After=docker.service network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
WorkingDirectory=__GITEA_DIR__
|
||||||
|
ExecStart=/usr/bin/docker compose up -d --remove-orphans
|
||||||
|
ExecStop=/usr/bin/docker compose down
|
||||||
|
TimeoutStartSec=300
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
51
uninstall.ps1
Normal file
51
uninstall.ps1
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#Requires -Version 5.1
|
||||||
|
|
||||||
|
param(
|
||||||
|
[switch]$Purge
|
||||||
|
)
|
||||||
|
|
||||||
|
$script:ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||||
|
Set-Location $script:ScriptDir
|
||||||
|
. "$script:ScriptDir\lib\common.ps1"
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Test-Dependencies
|
||||||
|
|
||||||
|
if ($Purge) {
|
||||||
|
Write-Warn "Будут удалены контейнеры и все данные (тома Docker)!"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Warn "Контейнеры будут удалены. Тома с данными сохранятся."
|
||||||
|
}
|
||||||
|
|
||||||
|
Confirm-OrExit "Продолжить?"
|
||||||
|
|
||||||
|
$task = Get-ScheduledTask -TaskName "Gitea" -ErrorAction SilentlyContinue
|
||||||
|
if ($task) {
|
||||||
|
throw "Задача Gitea зарегистрирована в планировщике. Сначала выполните: .\remove-service.ps1"
|
||||||
|
}
|
||||||
|
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
if ($Purge) {
|
||||||
|
foreach ($vol in Get-VolumeNames) {
|
||||||
|
$exists = docker volume inspect $vol 2>$null
|
||||||
|
if ($LASTEXITCODE -eq 0) {
|
||||||
|
Write-Info "Удаление тома: $vol"
|
||||||
|
docker volume rm $vol
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Write-Info "Полное удаление завершено."
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$volumes = (Get-VolumeNames) -join ", "
|
||||||
|
Write-Info "Контейнеры удалены. Данные сохранены в томах: $volumes"
|
||||||
|
Write-Info "Для полного удаления данных: .\uninstall.ps1 -Purge"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Err $_.Exception.Message
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
53
uninstall.sh
Normal file
53
uninstall.sh
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
source "$(dirname "$0")/lib/common.sh"
|
||||||
|
init_script_dir
|
||||||
|
check_dependencies
|
||||||
|
|
||||||
|
PURGE=false
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<'EOF'
|
||||||
|
Использование: ./uninstall.sh [--purge]
|
||||||
|
|
||||||
|
--purge Удалить контейнеры и Docker-тома с данными (необратимо)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
while [[ $# -gt 0 ]]; do
|
||||||
|
case "$1" in
|
||||||
|
--purge) PURGE=true; shift ;;
|
||||||
|
-h|--help) usage; exit 0 ;;
|
||||||
|
*) err "Неизвестный аргумент: $1"; usage; exit 1 ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ "$PURGE" == true ]]; then
|
||||||
|
warn "Будут удалены контейнеры и все данные (тома Docker)!"
|
||||||
|
else
|
||||||
|
warn "Контейнеры будут удалены. Тома с данными сохранятся."
|
||||||
|
fi
|
||||||
|
|
||||||
|
confirm_or_exit "Продолжить?"
|
||||||
|
|
||||||
|
if systemctl is-enabled gitea.service >/dev/null 2>&1; then
|
||||||
|
warn "Служба gitea.service включена. Сначала выполните: sudo ./remove-service.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
docker compose down
|
||||||
|
|
||||||
|
if [[ "$PURGE" == true ]]; then
|
||||||
|
read -r -a volumes <<< "$(get_volume_names)"
|
||||||
|
for vol in "${volumes[@]}"; do
|
||||||
|
if docker volume inspect "$vol" >/dev/null 2>&1; then
|
||||||
|
log "Удаление тома: $vol"
|
||||||
|
docker volume rm "$vol"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
log "Полное удаление завершено."
|
||||||
|
else
|
||||||
|
log "Контейнеры удалены. Данные сохранены в томах: $(get_volume_names)"
|
||||||
|
log "Для полного удаления данных: ./uninstall.sh --purge"
|
||||||
|
fi
|
||||||
Loading…
Reference in New Issue
Block a user