added mono-repo voting app CI/CD

This commit is contained in:
rezayaghobi-dev
2026-08-10 20:50:41 +03:30
parent 1cd4437a97
commit 40eeff17ed
4 changed files with 233 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
node_modules/
*.log
.env

View File

@@ -0,0 +1,183 @@
stages:
- build
- test
- scan
- deploy
- load-test
- backup
.build-service:
stage: build
image: docker:27-cli
services: [] # host-socket build, same pattern as ci-images — no DinD
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE/$SERVICE_NAME:latest" -t "$CI_REGISTRY_IMAGE/$SERVICE_NAME:$CI_COMMIT_SHORT_SHA" "$SERVICE_NAME"
- docker push "$CI_REGISTRY_IMAGE/$SERVICE_NAME:latest"
- docker push "$CI_REGISTRY_IMAGE/$SERVICE_NAME:$CI_COMMIT_SHORT_SHA"
build-vote:
extends: .build-service
variables:
SERVICE_NAME: vote
build-result:
extends: .build-service
variables:
SERVICE_NAME: result
build-worker:
extends: .build-service
variables:
SERVICE_NAME: worker
test-vote:
stage: test
image: docker:27-cli
services: []
script:
- docker network create test-net-$CI_JOB_ID
- docker run -d --name vote-test-$CI_JOB_ID --network test-net-$CI_JOB_ID "$CI_REGISTRY_IMAGE/vote:$CI_COMMIT_SHORT_SHA"
- sleep 5
- docker run --rm --network test-net-$CI_JOB_ID curlimages/curl:latest curl -sf "http://vote-test-$CI_JOB_ID:80/"
after_script:
- docker rm -f vote-test-$CI_JOB_ID || true
- docker network rm test-net-$CI_JOB_ID || true
test-result:
stage: test
image: docker:27-cli
services: []
script:
- docker network create test-net-$CI_JOB_ID
- docker run -d --name result-test-$CI_JOB_ID --network test-net-$CI_JOB_ID "$CI_REGISTRY_IMAGE/result:$CI_COMMIT_SHORT_SHA"
- sleep 5
- docker run --rm --network test-net-$CI_JOB_ID curlimages/curl:latest curl -sf "http://result-test-$CI_JOB_ID:80/"
after_script:
- docker rm -f result-test-$CI_JOB_ID || true
- docker network rm test-net-$CI_JOB_ID || true
test-worker:
stage: test
image: docker:27-cli
services: []
script:
- docker run -d --name worker-test-$CI_JOB_ID "$CI_REGISTRY_IMAGE/worker:$CI_COMMIT_SHORT_SHA"
- sleep 5
- |
STATUS=$(docker inspect -f '{{.State.Running}}' worker-test-$CI_JOB_ID)
if [ "$STATUS" != "true" ]; then
echo "worker exited unexpectedly on startup"
docker logs worker-test-$CI_JOB_ID
exit 1
fi
after_script:
- docker rm -f worker-test-$CI_JOB_ID || true
.scan-service:
stage: scan
image:
name: aquasec/trivy:latest
entrypoint: [""]
variables:
TRIVY_DB_REPOSITORY: "ghcr.io/aquasecurity/trivy-db:2"
TRIVY_CACHE_DIR: ".trivycache/"
cache:
key: trivy-db-cache
paths:
- .trivycache/
script:
- trivy image --exit-code 1 --ignore-unfixed --severity CRITICAL,HIGH --format table "$CI_REGISTRY_IMAGE/$SERVICE_NAME:$CI_COMMIT_SHORT_SHA"
scan-vote:
extends: .scan-service
variables:
SERVICE_NAME: vote
scan-result:
extends: .scan-service
variables:
SERVICE_NAME: result
scan-worker:
extends: .scan-service
variables:
SERVICE_NAME: worker
deploy-dev:
stage: deploy
image: docker:27-cli
services: []
variables:
IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
VOTE_PORT: "5100"
RESULT_PORT: "5101"
environment:
name: dev
script:
- docker compose -p voting-dev -f docker-compose.deploy.yml up -d
- sleep 10
- docker compose -p voting-dev -f docker-compose.deploy.yml ps
- docker compose -p voting-dev -f docker-compose.deploy.yml exec -T vote curl -sf http://localhost:80/
- docker compose -p voting-dev -f docker-compose.deploy.yml exec -T result curl -sf http://localhost:80/
after_script:
- docker compose -p voting-dev -f docker-compose.deploy.yml down -v
deploy-staging:
stage: deploy
image: docker:27-cli
services: []
variables:
IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
VOTE_PORT: "5200"
RESULT_PORT: "5201"
environment:
name: staging
url: "http://192.168.100.6:5200"
when: manual
script:
- docker compose -p voting-staging -f docker-compose.deploy.yml up -d
- sleep 10
- docker compose -p voting-staging -f docker-compose.deploy.yml exec -T vote curl -sf http://localhost:80/
- docker compose -p voting-staging -f docker-compose.deploy.yml exec -T result curl -sf http://localhost:80/
deploy-prod:
stage: deploy
image: docker:27-cli
services: []
variables:
IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
VOTE_PORT: "5300"
RESULT_PORT: "5301"
environment:
name: production
url: "http://192.168.100.6:5300"
when: manual
script:
- docker compose -p voting-prod -f docker-compose.deploy.yml up -d
- sleep 10
- docker compose -p voting-prod -f docker-compose.deploy.yml exec -T vote curl -sf http://localhost:80/
- docker compose -p voting-prod -f docker-compose.deploy.yml exec -T result curl -sf http://localhost:80/
load-test-staging:
stage: load-test
image:
name: grafana/k6:latest
entrypoint: [""]
when: manual
needs: ["deploy-staging"]
script:
- k6 run -e TARGET_HOST=192.168.100.6 -e VOTE_PORT=5200 loadtest/vote-load-test.js
backup-prod-db:
stage: backup
image: docker:27-cli
services: []
when: manual
needs: ["deploy-prod"]
script:
- export BACKUP_FILE="voting-prod-$(date +%Y%m%d-%H%M%S).sql.gz"
- docker exec voting-prod-db-1 pg_dump -U postgres postgres | gzip > "$BACKUP_FILE"
- docker create --name mc-helper-$CI_JOB_ID --entrypoint sh minio/mc:RELEASE.2025-08-13T08-35-41Z-cpuv1 -c "sleep 300"
- docker start mc-helper-$CI_JOB_ID
- docker cp "$BACKUP_FILE" mc-helper-$CI_JOB_ID:/tmp/"$BACKUP_FILE"
- docker exec mc-helper-$CI_JOB_ID mc alias set localminio http://192.168.100.6:9500 "$MINIO_ACCESS_KEY" "$MINIO_SECRET_KEY"
- docker exec mc-helper-$CI_JOB_ID mc cp /tmp/"$BACKUP_FILE" localminio/postgres-backups/
- docker exec mc-helper-$CI_JOB_ID mc ls localminio/postgres-backups/
after_script:
- docker rm -f mc-helper-$CI_JOB_ID || true

View File

@@ -0,0 +1,8 @@
# jaraco.context / wheel are vendored copies bundled inside setuptools,
# not direct app dependencies. Fixing requires upgrading pip/setuptools,
# which needs files.pythonhosted.org — currently unreachable from this
# network (confirmed: pypi.org resolves fine, files.pythonhosted.org
# times out). Revisit when connectivity allows, or if these ever appear
# on the app's real runtime dependency surface.
CVE-2026-23949
CVE-2026-24049

View File

@@ -0,0 +1,39 @@
services:
redis:
image: redis:7-alpine
mem_limit: 64m
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
volumes:
- db-data:/var/lib/postgresql/data
mem_limit: 128m
vote:
image: "${CI_REGISTRY_IMAGE}/vote:${IMAGE_TAG}"
ports:
- "${VOTE_PORT}:80"
depends_on:
- redis
mem_limit: 96m
result:
image: "${CI_REGISTRY_IMAGE}/result:${IMAGE_TAG}"
ports:
- "${RESULT_PORT}:80"
depends_on:
- db
mem_limit: 96m
worker:
image: "${CI_REGISTRY_IMAGE}/worker:${IMAGE_TAG}"
depends_on:
- redis
- db
mem_limit: 128m
volumes:
db-data: