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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Только локальные значения. Не используйте их в dev, stage или production.
COMPOSE_PROJECT_NAME=portable-agent

POSTGRES_ADMIN_USER=platform_admin
POSTGRES_ADMIN_PASSWORD=local_admin_change_me
POSTGRES_PORT=5432

KEYCLOAK_DB_USER=keycloak
KEYCLOAK_DB_PASSWORD=local_keycloak_db_change_me
KEYCLOAK_ADMIN_USER=admin
KEYCLOAK_ADMIN_PASSWORD=local_keycloak_admin_change_me
KEYCLOAK_PORT=8081

TEMPORAL_DB_USER=temporal
TEMPORAL_DB_PASSWORD=local_temporal_db_change_me
TEMPORAL_NAMESPACE=portable-agent-local
TEMPORAL_PORT=7233
TEMPORAL_UI_PORT=8080

REDPANDA_PORT=19092
OPA_PORT=8181
OTEL_GRPC_PORT=4317
OTEL_HTTP_PORT=4318
PROMETHEUS_PORT=9090
GRAFANA_PORT=3000
GRAFANA_ADMIN_USER=admin
GRAFANA_ADMIN_PASSWORD=local_grafana_change_me
TEMPO_PORT=3200
LOKI_PORT=3100
17 changes: 6 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ permissions:

jobs:
chart:
name: Helm and k3d quality gate
name: Config quality gate
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
Expand All @@ -20,16 +20,11 @@ jobs:
version: v4.2.4
- name: Проверить Helm chart
shell: pwsh
run: ./scripts/check-chart.ps1
- name: Установить k3d
env:
K3D_VERSION: v5.9.0
run: |
curl -fsSLo /tmp/k3d-install.sh \
"https://raw.githubusercontent.com/k3d-io/k3d/${K3D_VERSION}/install.sh"
TAG="${K3D_VERSION}" bash /tmp/k3d-install.sh
- name: Проверить установку в k3d
run: ./scripts/check-config.ps1
- name: Проверить Compose
shell: pwsh
run: ./scripts/smoke-k3d.ps1 -ClusterName "pa-${{ github.run_id }}"
run: ./scripts/check-compose.ps1
docs:
uses: portable-agent/.github/.github/workflows/reusable-docs.yml@main
security:
uses: portable-agent/.github/.github/workflows/reusable-security.yml@main
29 changes: 29 additions & 0 deletions .github/workflows/full-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Full infrastructure smoke

on:
workflow_dispatch:
schedule:
- cron: "20 2 * * 1"

permissions:
contents: read

jobs:
k3d:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v6
- uses: azure/setup-helm@v5.0.1
with:
version: v4.2.4
- name: Установить k3d
env:
K3D_VERSION: v5.9.0
run: |
curl -fsSLo /tmp/k3d-install.sh "https://raw.githubusercontent.com/k3d-io/k3d/${K3D_VERSION}/install.sh"
TAG="${K3D_VERSION}" bash /tmp/k3d-install.sh
- name: Запустить smoke
shell: pwsh
run: ./scripts/smoke-k3d.ps1 -ClusterName "pa-${{ github.run_id }}"

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ site/
.tmp-site/
*.tgz
*.log
.env
37 changes: 27 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
# Deploy

Репозиторий хранит Helm charts и локальный k3d smoke-тест Portable Agent. Здесь нет бизнес-кода,
секретов и настроек реального production.
Репозиторий хранит локальную инфраструктуру, общий Helm chart и GitOps-описание Portable Agent.
Здесь нет бизнес-кода, секретов и настроек реального production.

## Текущий пакет

Первый пакет проверяет только путь `Helm -> Kubernetes`:
Платформа разработки включает:

- `helm lint` проверяет chart;
- `helm template` проверяет render;
- временный k3d-кластер устанавливает chart;
- smoke-тест читает контрольный ConfigMap;
- созданный тестом кластер всегда удаляется.
- Compose-профиль `core`: PostgreSQL, Redpanda, Keycloak, Temporal и OPA;
- Compose-профиль `observe`: OpenTelemetry, Prometheus, Grafana, Tempo и Loki;
- безопасный общий chart `charts/service`;
- Argo CD bootstrap `charts/gitops`;
- каталог окружений и генератор нового сервиса;
- быстрые проверки в каждом PR и полный k3d smoke по расписанию.

## Требования

Expand All @@ -21,10 +22,20 @@
- kubectl;
- PowerShell 7.

Проверка chart без кластера:
Создай локальный файл настроек и запусти инфраструктуру:

```powershell
pwsh ./scripts/check-chart.ps1
Copy-Item .env.example .env
pwsh ./scripts/start-local.ps1 -Observe
```

Файл `.env` локальный и не коммитится. Значения `dev` и `stage` должны приходить из secret
manager, а не из Git.

Все быстрые проверки:

```powershell
pwsh ./scripts/check-config.ps1
```

Полная проверка:
Expand All @@ -33,5 +44,11 @@ pwsh ./scripts/check-chart.ps1
pwsh ./scripts/smoke-k3d.ps1
```

Подготовить delivery-файлы нового сервиса:

```powershell
pwsh ./scripts/new-service.ps1 -Name sample-api -Image ghcr.io/portable-agent/sample-api -Port 8080
```

Архитектура и следующий шаг описаны в [docs/index.md](docs/index.md). Правила для разработчиков и
AI-агентов находятся в [AGENTS.md](AGENTS.md).
6 changes: 6 additions & 0 deletions charts/gitops/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v2
name: gitops
description: Argo CD bootstrap для окружений Portable Agent
type: application
version: 0.1.0

17 changes: 17 additions & 0 deletions charts/gitops/templates/project.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: {{ .Values.projectName }}
namespace: argocd
spec:
sourceRepos:
- {{ .Values.source.repoUrl | quote }}
destinations:
{{- range .Values.environments }}
- namespace: {{ printf "portable-agent-%s" .name | quote }}
server: {{ $.Values.destinationServer | quote }}
{{- end }}
clusterResourceWhitelist: []
namespaceResourceWhitelist:
- group: "*"
kind: "*"
40 changes: 40 additions & 0 deletions charts/gitops/templates/services.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{{- range $environment := .Values.environments }}
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: {{ $.Values.projectName }}-{{ $environment.name }}
namespace: argocd
spec:
generators:
- git:
repoURL: {{ $.Values.source.repoUrl | quote }}
revision: {{ $.Values.source.revision | quote }}
directories:
- path: {{ printf "%s/%s/services/*" $.Values.servicesPath $environment.name | quote }}
template:
metadata:
name: '{{`{{path.basename}}`}}-{{ $environment.name }}'
spec:
project: {{ $.Values.projectName }}
sources:
- repoURL: {{ $.Values.source.repoUrl | quote }}
targetRevision: {{ $.Values.source.revision | quote }}
path: {{ $.Values.source.chartPath | quote }}
helm:
valueFiles:
- '$values/{{`{{path}}`}}/values.yaml'
- repoURL: {{ $.Values.source.repoUrl | quote }}
targetRevision: {{ $.Values.source.revision | quote }}
ref: values
destination:
server: {{ $.Values.destinationServer | quote }}
namespace: {{ printf "portable-agent-%s" $environment.name | quote }}
syncPolicy:
syncOptions: [CreateNamespace=true]
{{- if $environment.autoSync }}
automated:
prune: true
selfHeal: true
{{- end }}
{{- end }}
8 changes: 8 additions & 0 deletions charts/gitops/tests/smoke-values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
source:
repoUrl: https://github.com/example/deploy.git
revision: main
chartPath: charts/service
environments:
- {name: local, autoSync: true}
- {name: dev, autoSync: true}
- {name: stage, autoSync: false}
29 changes: 29 additions & 0 deletions charts/gitops/values.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"required": ["projectName", "source", "environments"],
"properties": {
"projectName": {"type": "string", "pattern": "^[a-z0-9-]+$"},
"source": {
"type": "object",
"required": ["repoUrl", "revision", "chartPath"],
"properties": {
"repoUrl": {"type": "string", "minLength": 1},
"revision": {"type": "string", "minLength": 1},
"chartPath": {"type": "string", "minLength": 1}
}
},
"environments": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"required": ["name", "autoSync"],
"properties": {
"name": {"type": "string", "pattern": "^[a-z0-9-]+$"},
"autoSync": {"type": "boolean"}
}
}
}
}
}
8 changes: 8 additions & 0 deletions charts/gitops/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
projectName: portable-agent
source:
repoUrl: ""
revision: main
chartPath: charts/service
servicesPath: environments
environments: []
destinationServer: https://kubernetes.default.svc
7 changes: 7 additions & 0 deletions charts/service/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: v2
name: service
description: Общий Helm chart для stateless-сервисов Portable Agent
type: application
version: 0.1.0
appVersion: "1.0.0"

15 changes: 15 additions & 0 deletions charts/service/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{{- define "service.name" -}}
{{- default .Release.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- define "service.fullname" -}}
{{- if .Values.fullnameOverride }}{{ .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}{{ else }}{{ include "service.name" . }}{{ end }}
{{- end }}
{{- define "service.labels" -}}
app.kubernetes.io/name: {{ include "service.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version }}
{{- end }}
{{- define "service.account" -}}
{{- default (include "service.fullname" .) .Values.serviceAccount.name }}
{{- end }}
13 changes: 13 additions & 0 deletions charts/service/templates/configmap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{{- if .Values.config }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ include "service.fullname" . }}
labels:
{{- include "service.labels" . | nindent 4 }}
data:
{{- range $key, $value := .Values.config }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- end }}

88 changes: 88 additions & 0 deletions charts/service/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "service.fullname" . }}
labels:
{{- include "service.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app.kubernetes.io/name: {{ include "service.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
template:
metadata:
annotations:
checksum/config: {{ toJson .Values.config | sha256sum }}
{{- with .Values.podAnnotations }}
{{- toYaml .Values.podAnnotations | nindent 8 }}
{{- end }}
labels:
{{- include "service.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml .Values.podLabels | nindent 8 }}
{{- end }}
spec:
serviceAccountName: {{ include "service.account" . }}
automountServiceAccountToken: false
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
{{- with .Values.imagePullSecrets }}
imagePullSecrets: {{ toYaml . | nindent 8 }}
{{- end }}
containers:
- name: service
image: {{ printf "%s:%s" .Values.image.repository .Values.image.tag | quote }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: [ALL]
ports:
- name: http
containerPort: {{ .Values.containerPort }}
{{- if .Values.config }}
envFrom:
- configMapRef:
name: {{ include "service.fullname" . }}
{{- end }}
env:
{{- if .Values.otel.enabled }}
- name: OTEL_EXPORTER_OTLP_ENDPOINT
value: {{ .Values.otel.endpoint | quote }}
- name: OTEL_SERVICE_NAME
value: {{ include "service.fullname" . | quote }}
{{- end }}
{{- range .Values.secretRefs }}
- name: {{ .env }}
valueFrom:
secretKeyRef:
name: {{ .name }}
key: {{ .key }}
{{- end }}
{{- with .Values.extraEnv }}
{{- toYaml .Values.extraEnv | nindent 12 }}
{{- end }}
{{- if .Values.probes.enabled }}
readinessProbe:
httpGet: {path: {{ .Values.probes.path }}, port: http}
initialDelaySeconds: {{ .Values.probes.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.periodSeconds }}
livenessProbe:
httpGet: {path: {{ .Values.probes.livenessPath }}, port: http}
initialDelaySeconds: {{ .Values.probes.initialDelaySeconds }}
periodSeconds: {{ .Values.probes.periodSeconds }}
{{- end }}
resources: {{ toYaml .Values.resources | nindent 12 }}
volumeMounts:
- name: temp
mountPath: /tmp
volumes:
- name: temp
emptyDir: {}
nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }}
tolerations: {{ toYaml .Values.tolerations | nindent 8 }}
affinity: {{ toYaml .Values.affinity | nindent 8 }}
Loading
Loading