Skip to content

Latest commit

 

History

History
431 lines (326 loc) · 14.9 KB

File metadata and controls

431 lines (326 loc) · 14.9 KB

Maven и Debian-репозитории (devops)

На devops.local в стеке devops:

Что ПО URL Данные на диске
Maven / Gradle Reposilite 3.x https://devops.local/maven/ /opt/compose/devops/data/maven
Debian APT reprepro + nginx https://devops.local/debian/ /opt/compose/devops/data/debian
GPG ключ APT gnupg в контейнере https://devops.local/debian/gpg-pubkey.asc /opt/compose/devops/data/debian-gpg

Веб-морды только через nginx HTTPS. Reposilite и debian-www в Docker-сети portal (nginx резолвит devops-maven / devops-debian-www); на хосте ещё 127.0.0.1:8083 / :8084 для отладки. CA: docs/registry-tls.md.

Портал: https://devops.local/ — секции Middleware и DevOps.

make devops       # runner, mcp, maven, debian, registry, portainer, TLS
make middleware   # nginx: /maven/, /debian/ + портал

Порядок важен: сначала devops (TLS), потом middleware. make deploy делает так сам.

Перед первым деплоем: make setup (Maven username/password в .env).


1. Maven (Reposilite)

1.1. Что это

Лёгкий Maven 2-репозиторий с UI. По умолчанию три хранилища:

  • releases — релизные версии (1.2.3, без -SNAPSHOT)
  • snapshots — -SNAPSHOT
  • central — прокси Maven Central (read-through)

UI: https://devops.local/maven/
Логин: maven_username / maven_password из secrets (--token при старте контейнера).

После первого входа в UI → Console:

token-generate ci m

получите отдельный токен для CI (можно с --secret=...). Management-токен m умеет всё; для publish хватает прав на репозиторий.

1.2. ~/.m2/settings.xml (разработчик / CI)

<settings>
  <servers>
    <server>
      <id>devops-releases</id>
      <username>darvik</username>
      <password>ВАШ_ПАРОЛЬ</password>
    </server>
    <server>
      <id>devops-snapshots</id>
      <username>darvik</username>
      <password>ВАШ_ПАРОЛЬ</password>
    </server>
  </servers>
  <mirrors>
    <mirror>
      <id>devops-central</id>
      <name>Reposilite central proxy</name>
      <url>https://devops.local/maven/central</url>
      <mirrorOf>central</mirrorOf>
    </mirror>
  </mirrors>
</settings>

id сервера должен совпасть с id в pom.xml / distributionManagement.

Репозиторий отдаётся по HTTPS с приватным CA. Сначала доверьтесь CA (registry-tls.md): Windows — в «Доверенные корневые», Linux — update-ca-certificates. JVM после этого обычно подхватывает системный store.

Если mvn всё ещё пишет PKIX / unable to find valid certification path:

sudo curl -fsSL http://devops.local/ca.crt -o /tmp/devops.local.crt
sudo keytool -importcert -noprompt -alias devops.local \
  -keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit \
  -file /tmp/devops.local.crt

Пример <repository>:

<repository>
  <id>devops-releases</id>
  <url>https://devops.local/maven/releases</url>
  <releases><enabled>true</enabled></releases>
  <snapshots><enabled>false</enabled></snapshots>
</repository>

1.3. Публикация из pom.xml

<distributionManagement>
  <repository>
    <id>devops-releases</id>
    <url>https://devops.local/maven/releases</url>
  </repository>
  <snapshotRepository>
    <id>devops-snapshots</id>
    <url>https://devops.local/maven/snapshots</url>
  </snapshotRepository>
</distributionManagement>
mvn -DskipTests deploy

Версия 1.0.0-SNAPSHOT → snapshots, 1.0.0 → releases.

1.4. Gradle

settings.gradle.kts / build.gradle.kts:

repositories {
    maven { url = uri("https://devops.local/maven/releases") }
    maven { url = uri("https://devops.local/maven/snapshots") }
    mavenCentral()
}

publishing {
    repositories {
        maven {
            name = "devops"
            url = uri(
                if (version.toString().endsWith("-SNAPSHOT"))
                    "https://devops.local/maven/snapshots"
                else
                    "https://devops.local/maven/releases"
            )
            credentials {
                username = System.getenv("MAVEN_USERNAME")
                password = System.getenv("MAVEN_PASSWORD")
            }
            isAllowInsecureProtocol = true
        }
    }
}
export MAVEN_USERNAME=darvik MAVEN_PASSWORD='...'
./gradlew publish

1.5. curl (без Maven)

curl -u darvik:'пароль' --upload-file target/my-lib-1.0.0.jar \
  "https://devops.local/maven/releases/com/example/my-lib/1.0.0/my-lib-1.0.0.jar"

Нужны ещё POM и checksums; проще mvn deploy.

1.6. Gitea Actions

# .gitea/workflows/maven-publish.yml
name: Publish Maven
on:
  push:
    tags: ["v*"]
jobs:
  publish:
    runs-on: devops.local
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "21"
      - name: Trust devops.local CA
        run: |
          sudo curl -fsSL http://devops.local/ca.crt -o /usr/local/share/ca-certificates/devops.local.crt
          sudo update-ca-certificates
          sudo keytool -importcert -noprompt -alias devops.local \
            -keystore "$JAVA_HOME/lib/security/cacerts" -storepass changeit \
            -file /usr/local/share/ca-certificates/devops.local.crt || true
      - name: settings.xml
        run: |
          mkdir -p ~/.m2
          cat > ~/.m2/settings.xml <<EOF
          <settings>
            <servers>
              <server>
                <id>devops-releases</id>
                <username>${{ secrets.MAVEN_USERNAME }}</username>
                <password>${{ secrets.MAVEN_PASSWORD }}</password>
              </server>
            </servers>
          </settings>
          EOF
      - run: mvn -B -DskipTests deploy

Секреты в Gitea: Settings → Secrets (MAVEN_USERNAME, MAVEN_PASSWORD). Runner label: devops.local (как в gitea_runner_labels).

Runner крутится на том же хосте: в job используйте https://devops.local/maven/... и шаг Trust devops.local CA выше (job-контейнер не видит host trust store).

1.7. Зависимость в другом проекте

<repositories>
  <repository>
    <id>devops-releases</id>
    <url>https://devops.local/maven/releases</url>
  </repository>
</repositories>

<dependency>
  <groupId>com.example</groupId>
  <artifactId>my-lib</artifactId>
  <version>1.0.0</version>
</dependency>

Если артефакт публичный в Reposilite (visibility PUBLIC) — пароль для download не нужен. Для PRIVATE — тот же <server> в settings.xml.

1.8. Эксплуатация

Действие Как
Логи docker logs -f devops-maven
Сброс UI-конфига удалить /opt/compose/devops/data/maven/configuration.cdn и make devops (seed вернёт basePath: /maven/)
Память JAVA_OPTS=-Xmx256M в compose
Бэкап скопировать data/maven

2. Debian APT (reprepro)

2.1. Что это

Подписанный APT-репозиторий одной серии:

  • Origin / Label: devops.local
  • Codename: bookworm (переменные в inventory/group_vars/devops.yml)
  • Component: main
  • Arch: amd64 source

Контейнер devops-debian-repo раз в 15 с забирает *.deb из incoming/ и делает reprepro includedeb.
devops-debian-www отдаёт дерево наружу. Nginx портала проксирует /debian/.

GPG-ключ создаётся один раз (без passphrase) и лежит в /opt/compose/devops/data/debian-gpg. Публичная часть: /debian/gpg-pubkey.asc.

2.2. Подключить репозиторий на клиенте (Debian/Ubuntu)

sudo mkdir -p /etc/apt/keyrings /usr/local/share/ca-certificates

sudo curl -fsSL http://devops.local/ca.crt \
  -o /usr/local/share/ca-certificates/devops.local.crt
sudo update-ca-certificates

curl -fsSL https://devops.local/debian/gpg-pubkey.asc \
  | sudo gpg --dearmor -o /etc/apt/keyrings/devops.local.gpg

echo "deb [signed-by=/etc/apt/keyrings/devops.local.gpg] https://devops.local/debian bookworm main" \
  | sudo tee /etc/apt/sources.list.d/devops.local.list

sudo apt update
apt-cache policy

Старый apt-key add не используйте. signed-by= обязателен на bookworm/noble.

Установка пакета:

sudo apt install имя-пакета

2.3. Залить .deb

Вариант A — incoming (проще)

scp myapp_1.0.0_amd64.deb darvik@devops.local:/opt/compose/devops/data/debian/incoming/
# через ~15 с пакет появится в dists/bookworm/main

Вариант B — сразу reprepro

ssh darvik@devops.local
sudo docker exec -i devops-debian-repo \
  reprepro -b /repo includedeb bookworm /repo/incoming/myapp_1.0.0_amd64.deb

Положить файл в incoming и exec — если не хотите ждать цикл.

Вариант C — с Windows

scp .\myapp_1.0.0_amd64.deb darvik@devops.local:/opt/compose/devops/data/debian/incoming/

Проверка:

curl -s https://devops.local/debian/dists/bookworm/main/binary-amd64/Packages

2.4. Сборка .deb (кратко)

Минимум: debian/ в исходниках + dpkg-buildpackage, или nfpm, или fpm.

nfpm example nfpm.yaml:

name: myapp
arch: amd64
platform: linux
version: 1.0.0
maintainer: darvik
description: example
contents:
  - src: ./myapp
    dst: /usr/bin/myapp
nfpm package -p deb -f nfpm.yaml

Имя файла лучше в формате Debian: имя_версия_архитектура.deb.

2.5. Gitea Actions: publish .deb

name: Publish deb
on:
  push:
    tags: ["v*"]
jobs:
  deb:
    runs-on: devops.local
    steps:
      - uses: actions/checkout@v4
      - name: Build deb
        run: |
          # ваш nfpm / dpkg-buildpackage
          nfpm package -p deb -f nfpm.yaml
      - name: Ingest
        run: |
          cp ./*.deb /opt/compose/devops/data/debian/incoming/
          sleep 20
          curl -fsSL "http://127.0.0.1/debian/dists/bookworm/main/binary-amd64/Packages" | grep -E '^Package:'

Job идёт на runner на devops.local, путь /opt/compose/... доступен, если runner не в изоляции. Если job в контейнере catthehacker/ubuntu:act-latest, bind-mount хоста нет — тогда:

      - name: Ingest via docker
        run: |
          docker cp ./*.deb devops-debian-repo:/repo/incoming/

(docker.sock у runner уже примонтирован.)

2.6. Несколько дистрибутивов

В devops.yml:

debian_codename: bookworm   # или jammy, noble, ...

Для нескольких codename сразу — добавьте ещё один блок в stacks/devops/debian/conf/distributions.j2 (пустая строка между блоками) и кладите пакеты так:

docker exec -i devops-debian-repo reprepro -b /repo includedeb jammy /repo/incoming/foo.deb

Цикл incoming/*.deb всегда кладёт в DEBIAN_CODENAME (один codename). Для второго — только ручной includedeb.

2.7. Эксплуатация и безопасность

Тема Детали
Логи ingest docker logs -f devops-debian-repo
Список пакетов docker exec devops-debian-repo reprepro -b /repo list bookworm
Удалить пакет docker exec devops-debian-repo reprepro -b /repo remove bookworm имя
Ключ бэкап data/debian-gpg + data/debian; потеря ключа = клиенты перестанут доверять Release
conf/ и db/ закрыты в nginx, снаружи не отдаются
HTTP без TLS для LAN ок; подпись Release защищает метаданные, но ключ лучше раздавать по доверенному каналу (вы уже в LAN)
Passphrase ключа сейчас пустая, чтобы reprepro подписывал без tty. Не выносите data/debian-gpg за пределы хоста

3. Переменные

inventory/group_vars/devops.yml и all.yml:

Variable Default Назначение
maven_http_port 8083 Reposilite на localhost (nginx → /maven/)
debian_http_port 8084 debian-www на localhost (nginx → /debian/)
debian_codename bookworm APT suite
debian_components main компонент
debian_architectures amd64 source архитектуры
debian_gpg_name / debian_gpg_email devops.local / packages@devops.local uid ключа

Секреты: maven_username, maven_password, плюс токены runner/MCP.


4. Типичные ошибки

Maven 401 / 403 — неверный token или snapshot в releases (Reposilite не пускает SNAPSHOT в releases).

Maven «Blocked mirror» / HTTP disabled — Maven 3.8.1+; см. mirror blocked: false выше.

/maven/ отдаёт портал — nginx не пересоздан после смены конфига: make middleware (роль force-recreate nginx) или docker restart middleware-nginx.

APT NO_PUBKEY / EXPKEYSIG — не импортирован gpg-pubkey.asc или ключ перевыпустили (тогда заново dearmor + apt update).

APT пустой Packages — .deb ещё в incoming/ (смотрите логи devops-debian-repo) или архитектура не amd64.

Portal debian/maven offline — nginx должен быть в сети portal вместе с devops-maven / devops-debian-www. Сначала make devops, потом make middleware (nginx force-recreate). Не используйте host.docker.internal:8083 — порты только на 127.0.0.1, из контейнера туда не попасть.

gitea-mcp -bind — в текущем образе флага нет; command: ["/app/gitea-mcp", "-t", "http", "-p", "8080"].