Compare commits

1 Commits

Author SHA1 Message Date
75a5881d40 add dev 2025-11-04 17:14:53 +03:00
14 changed files with 234 additions and 89 deletions

View File

@ -1,43 +1,89 @@
## Universal .drone.yml for all project types
## Configure your project via service.yaml (see ci-templates/docs/requirements.md)
kind: pipeline
type: kubernetes
name: ci
name: deploy-frontend
# Триггеры: запускать на push в ветки main и develop
trigger:
branch:
- master
- develop
event:
- push
steps:
- name: prepare
image: alpine:3.19
environment:
GITEA_TOKEN:
from_secret: GITEA_TOKEN
commands:
- apk add --no-cache git bash yq
- git clone --depth 1 https://token:$GITEA_TOKEN@git.vigdorov.ru/vigdorov/ci-templates.git .ci
- chmod +x .ci/scripts/*.sh
- bash .ci/scripts/prepare.sh
- name: build
image: gcr.io/kaniko-project/executor:v1.23.2-debug
depends_on: [prepare]
environment:
HARBOR_USER:
# --- Шаг 1: Сборка и отправка образа в Harbor ---
# Этот шаг выполняется для любой из веток (main или develop)
- name: build-and-push
image: plugins/docker
settings:
# Укажите ваш домен Harbor
registry: registry.vigdorov.ru
# Имя репозитория в Harbor (например, в проекте library)
repo: registry.vigdorov.ru/library/examples-for-kids-app
# Тег будет равен первым 7 символам хеша коммита (например, a1b2c3d)
tags:
- ${DRONE_COMMIT_SHA:0:7}
# Используем секреты, которые мы создали в Drone
username:
from_secret: HARBOR_USER
HARBOR_PASSWORD:
password:
from_secret: HARBOR_PASSWORD
commands:
- /busybox/sh .ci/scripts/build.sh
- name: deploy
image: alpine:3.19
depends_on: [build]
# --- Шаг 2: Развертывание в DEV-окружение ---
- name: deploy-dev
image: alpine/k8s:1.28.2 # Образ с kubectl и другими утилитами
# Запускать этот шаг ТОЛЬКО для ветки 'develop'
when:
branch:
- develop
environment:
KUBE_CONFIG:
# Используем секрет с kubeconfig
KUBECONFIG:
from_secret: KUBE_CONFIG
commands:
- apk add --no-cache bash yq kubectl helm
- bash .ci/scripts/deploy.sh
# Готовим переменные для dev-окружения
- 'export APP_NAMESPACE="dev-ns"' # Будем деплоить в отдельный неймспейс
- 'export HOSTNAME="dev_examples-for-kids.vigdorov.ru"'
- 'export IMAGE_TAG="${DRONE_COMMIT_SHA:0:7}"'
- 'export IMAGE_NAME="ci.vigdorov.ru/library/examples-for-kids-app"'
- 'export SECRET_NAME="wildcard-cert"'
# Создаем неймспейс, если его нет
- 'kubectl create namespace $APP_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -'
# Заменяем метки в шаблонах на реальные значения и применяем
- 'sed -e "s|__IMAGE__|$IMAGE_NAME:$IMAGE_TAG|g" k8s/deployment.yaml | kubectl apply -n $APP_NAMESPACE -f -'
- 'kubectl apply -n $APP_NAMESPACE -f k8s/service.yaml'
- 'sed -e "s|__HOSTNAME__|$HOSTNAME|g" -e "s|__SECRET_NAME__|$SECRET_NAME|g" k8s/ingress.yaml | kubectl apply -n $APP_NAMESPACE -f -'
- 'echo "Deployed to DEV: https://$HOSTNAME"'
trigger:
branch: [master, develop]
event: [push]
# --- Шаг 3: Развертывание в PROD-окружение ---
- name: deploy-prod
image: alpine/k8s:1.28.2
# Запускать этот шаг ТОЛЬКО для ветки 'main'
when:
branch:
- master
environment:
KUBE_CONFIG_CONTENT:
from_secret: KUBE_CONFIG
commands:
# Создаем kubeconfig файл из секрета
- 'mkdir -p ~/.kube'
- 'echo "$KUBE_CONFIG_CONTENT" > ~/.kube/config'
- 'chmod 600 ~/.kube/config'
# Заменяем localhost на внешний IP сервера
- 'sed -i "s|https://127.0.0.1:6443|https://192.168.1.55:6443|g" ~/.kube/config'
# Готовим переменные для prod-окружения
- 'export APP_NAMESPACE="prod-ns"'
- 'export HOSTNAME="examples-for-kids.vigdorov.ru"'
- 'export IMAGE_TAG="${DRONE_COMMIT_SHA:0:7}"'
- 'export IMAGE_NAME="registry.vigdorov.ru/library/examples-for-kids-app"'
- 'export SECRET_NAME="wildcard-cert"'
# Проверяем подключение к кластеру
- 'kubectl cluster-info'
# Создаем неймспейс
- 'kubectl create namespace $APP_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -'
# Разворачиваем приложение
- 'sed -e "s|__IMAGE__|$IMAGE_NAME:$IMAGE_TAG|g" k8s/deployment.yaml | kubectl apply -n $APP_NAMESPACE -f -'
- 'kubectl apply -n $APP_NAMESPACE -f k8s/service.yaml'
- 'sed -e "s|__HOSTNAME__|$HOSTNAME|g" -e "s|__SECRET_NAME__|$SECRET_NAME|g" k8s/ingress.yaml | kubectl apply -n $APP_NAMESPACE -f -'
- 'echo "Deployed to PROD: https://$HOSTNAME"'

37
.github/workflows/deploy.yml vendored Normal file
View File

@ -0,0 +1,37 @@
# This is a basic workflow to help you get started with Actions
name: Deploy to pages
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ master ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
- name: Install and Build 🔧 # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
run: |
npm i
npm run build
- name: Deploy 🚀
uses: JamesIves/github-pages-deploy-action@3.7.1
with:
ACCESS_TOKEN: ${{ secrets.GIT_TOKEN_V1 }}
BRANCH: gh-pages # The branch the action should deploy to.
FOLDER: build # The folder the action should deploy.
CLEAN: true # Automatically remove deleted files from the deploy branch

2
.gitignore vendored
View File

@ -1,6 +1,6 @@
/node_modules
/.vscode
/dist
/build
/coverage
**/junit.xml
.dependencies-cache

View File

@ -1,42 +0,0 @@
# Examples for Kids
Веб-приложение для детей — тренажер решения математических примеров.
## Назначение
Интерактивный веб-интерфейс для практики арифметики. Дети решают примеры, получают обратную связь.
## Стек
- **Frontend:** Vanilla JS + Webpack
- **Styling:** Bootstrap 5
- **Testing:** Jest
- **Build:** Webpack 5
## Команды
```bash
npm install # Установка зависимостей
npm run dev # Запуск dev-сервера
npm run build # Production сборка
npm run test # Запуск тестов
npm run lint # Проверка линтером
```
## Структура
```
examples-for-kids/
├── src/ # Исходный код
├── public/ # Статические файлы
├── coverage/ # Отчеты покрытия тестами
├── service.yaml # Конфиг для ci-templates
└── .drone.yml # CI/CD пайплайн (универсальный)
```
## Деплой
- Тип: `web-frontend` (ci-templates)
- Dockerfile, nginx.conf, Helm chart — предоставляются ci-templates автоматически
- Конфигурация через `service.yaml`
- Домен: examples-for-kids.vigdorov.ru

14
Dockerfile Normal file
View File

@ -0,0 +1,14 @@
# build environment
FROM node:18 as builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# production environment
FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

6
docker-compose.prod.yml Normal file
View File

@ -0,0 +1,6 @@
version: '3.8'
services:
frontend:
image: examples-for-kids:${BUILD_NUMBER:-latest}
ports:
- "3000:80"

View File

@ -0,0 +1,6 @@
version: '3.8'
services:
frontend:
image: examples-for-kids:${BUILD_NUMBER:-latest}
ports:
- "3001:80"

22
k8s/deployment.yaml Normal file
View File

@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: examples-for-kids-app
spec:
replicas: 1
selector:
matchLabels:
app: examples-for-kids-app
template:
metadata:
labels:
app: examples-for-kids-app
spec:
imagePullSecrets:
- name: harbor-creds # Имя секрета, который мы создали на Шаге 1
containers:
- name: examples-for-kids-app
# __IMAGE__ - это метка, которую заменит Drone
image: __IMAGE__
ports:
- containerPort: 80

23
k8s/ingress.yaml Normal file
View File

@ -0,0 +1,23 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: examples-for-kids-ingress
spec:
ingressClassName: traefik
tls:
- hosts:
# __HOSTNAME__ - метка для домена
- __HOSTNAME__
# __SECRET_NAME__ - метка для имени секрета с сертификатом
secretName: __SECRET_NAME__
rules:
- host: __HOSTNAME__
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: examples-for-kids-app-service
port:
number: 80

11
k8s/service.yaml Normal file
View File

@ -0,0 +1,11 @@
apiVersion: v1
kind: Service
metadata:
name: examples-for-kids-app-service
spec:
selector:
app: examples-for-kids-app
ports:
- protocol: TCP
port: 80
targetPort: 80

29
nginx.conf Normal file
View File

@ -0,0 +1,29 @@
events {}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
listen 80;
location /stub_status {
stub_status on;
allow all;
}
location / {
root /usr/share/nginx/html;
index index.html;
try_files $uri $uri/ $uri.html =404;
}
location /assets/ {
root /usr/share/nginx/html;
}
location ~* \.(js|css|ico|png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)$ {
root /usr/share/nginx/html;
}
}
}

View File

@ -1,7 +0,0 @@
service:
name: examples-for-kids
type: web-frontend
deploy:
namespace: examples-for-kids
domain: examples-for-kids.vigdorov.ru

View File

@ -8,7 +8,7 @@ module.exports = {
entry: './src/script.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
path: path.resolve(__dirname, 'build'),
},
devServer: {
open: true,