Revert .gitlab-ci.yml to working configuration

Keep authentication fix in Program.cs but use original CI/CD pipeline configuration that builds from Dockerfile

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
SysAdmin 2025-10-01 13:18:19 +01:00
parent d31c0b4aeb
commit c31df615ab

View File

@ -1,265 +1,152 @@
# GitLab CI/CD Pipeline for LittleShop
# Builds and deploys to Hostinger VPS
stages: stages:
- build - build
- test
- deploy - deploy
variables: variables:
DOCKER_HOST: unix:///var/run/docker.sock DOCKER_HOST: unix:///var/run/docker.sock
DOCKER_DRIVER: overlay2
# Registry configuration
REGISTRY_URL: "localhost:5000"
IMAGE_NAME: "littleshop"
# Hostinger deployment configuration
DEPLOY_HOST: "10.13.13.1"
DEPLOY_PORT: "2255"
CONTAINER_NAME: "littleshop-admin"
# Build from .NET source and create Docker image
build: build:
stage: build stage: build
image: mcr.microsoft.com/dotnet/sdk:9.0 image: docker:24
services:
- docker:24-dind
before_script:
- apt-get update && apt-get install -y docker.io
- docker --version
script: script:
- echo "Building LittleShop application..." - echo "Building LittleShop Docker image"
- cd LittleShop - docker build -t localhost:5000/littleshop:latest .
- dotnet publish -c Production -o ../publish --verbosity minimal
- cd ..
# Create optimized Dockerfile
- | - |
cat > Dockerfile << 'EOF' if [ -n "$CI_COMMIT_TAG" ]; then
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine echo "Tagging as version $CI_COMMIT_TAG"
WORKDIR /app docker tag localhost:5000/littleshop:latest localhost:5000/littleshop:$CI_COMMIT_TAG
COPY ./publish . fi
- echo "Build complete"
# Create required directories and user
RUN mkdir -p /app/data /app/wwwroot/uploads && \
adduser -D -u 1658 appuser && \
chown -R appuser:appuser /app
USER appuser
EXPOSE 8080
ENTRYPOINT ["dotnet", "LittleShop.dll"]
EOF
# Build and tag Docker image
- export VERSION="${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
- docker build -t ${REGISTRY_URL}/${IMAGE_NAME}:${VERSION} .
- docker tag ${REGISTRY_URL}/${IMAGE_NAME}:${VERSION} ${REGISTRY_URL}/${IMAGE_NAME}:latest
# Save image for deployment
- docker save ${REGISTRY_URL}/${IMAGE_NAME}:${VERSION} -o littleshop.tar
- echo "Build complete for version ${VERSION}"
artifacts:
paths:
- littleshop.tar
- publish/
expire_in: 1 hour
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG' - if: '$CI_COMMIT_TAG'
tags: tags:
- docker - docker
# Run tests deploy:vps:
test:
stage: test
image: mcr.microsoft.com/dotnet/sdk:9.0
script:
- echo "Running tests..."
- cd LittleShop.Tests
- dotnet test --no-restore --verbosity normal || true
allow_failure: true
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG'
# Deploy to Hostinger VPS
deploy:hostinger:
stage: deploy stage: deploy
image: alpine:latest image: docker:24
dependencies:
- build
before_script: before_script:
- apk add --no-cache openssh-client sshpass curl - apk add --no-cache openssh-client bash curl
# Setup SSH key if provided - echo "$VPS_SSH_KEY_B64" | base64 -d > /tmp/deploy_key
- | - chmod 600 /tmp/deploy_key
if [ -n "$HOSTINGER_SSH_KEY" ]; then - mkdir -p ~/.ssh
echo "$HOSTINGER_SSH_KEY" | base64 -d > /tmp/hostinger_key - chmod 700 ~/.ssh
chmod 600 /tmp/hostinger_key - ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts
export SSH_CMD="ssh -i /tmp/hostinger_key"
export SCP_CMD="scp -i /tmp/hostinger_key"
else
export SSH_CMD="sshpass -p $DEPLOY_PASSWORD ssh"
export SCP_CMD="sshpass -p $DEPLOY_PASSWORD scp"
fi
script: script:
- export VERSION="${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}" - export VERSION="${CI_COMMIT_TAG:-$CI_COMMIT_SHORT_SHA}"
- echo "Deploying version ${VERSION} to Hostinger..." - echo "Deploying version $VERSION to VPS"
- echo "Building image from source..."
- docker build -t littleshop:$VERSION .
# Transfer Docker image to server - echo "Copying image to VPS via SSH..."
- $SCP_CMD -P ${DEPLOY_PORT} -o StrictHostKeyChecking=no littleshop.tar ${DEPLOY_USER}@${DEPLOY_HOST}:/tmp/ - docker save littleshop:$VERSION | ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" "docker load"
# Deploy on server - echo "Deploying on VPS..."
- | - |
$SSH_CMD -p ${DEPLOY_PORT} -o StrictHostKeyChecking=no ${DEPLOY_USER}@${DEPLOY_HOST} << DEPLOY_SCRIPT ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" bash -s << EOF
set -e set -e
export VERSION="$VERSION"
# Load Docker image # Tag the image
echo "${DEPLOY_PASSWORD}" | sudo -S docker load -i /tmp/littleshop.tar docker tag littleshop:\$VERSION localhost:5000/littleshop:\$VERSION
docker tag littleshop:\$VERSION localhost:5000/littleshop:latest
# Stop and remove existing container # Push to local registry
echo "${DEPLOY_PASSWORD}" | sudo -S docker stop ${CONTAINER_NAME} 2>/dev/null || true echo "Pushing to local Docker registry..."
echo "${DEPLOY_PASSWORD}" | sudo -S docker rm ${CONTAINER_NAME} 2>/dev/null || true docker push localhost:5000/littleshop:\$VERSION
docker push localhost:5000/littleshop:latest
# Run new container with authentication fix and all environment variables # Navigate to deployment directory
echo "${DEPLOY_PASSWORD}" | sudo -S docker run -d \ cd /opt/littleshop
--name ${CONTAINER_NAME} \
--restart unless-stopped \
-p 5100:8080 \
-v /var/opt/littleshop/data:/app/data \
-v /var/opt/littleshop/uploads:/app/wwwroot/uploads \
-e ASPNETCORE_ENVIRONMENT=Production \
-e WebPush__VapidPublicKey='BDJtQu7zV0H3KF4FkrZ8nPwP3YD_3cEz3hqJvQ6L_gvNpG8ANksQB-FZy2-PDmFAu6duiN4p3mkcNAGnN4YRbws' \
-e WebPush__VapidPrivateKey='Hm_ttUKUqoLn5R8WQP5O1SIGxm0kVJXMZGCPMD1tUDY' \
-e WebPush__VapidSubject='mailto:admin@littleshop.local' \
-e ConnectionStrings__DefaultConnection='Data Source=/app/data/littleshop-production.db' \
-e Jwt__Key='2D7B5FE9C4A3E1D8B6A947F2C8E5D3A1B9F7E4C2D8A6B3E9F1C7D5A2E8B4F6C9' \
-e Jwt__Audience='LittleShop-Production' \
-e Jwt__ExpiryInHours='24' \
-e Jwt__Issuer='LittleShop-Production' \
-e SilverPay__AllowUnsignedWebhooks='false' \
-e SilverPay__WebhookSecret='04126be1b2ca9a586aaf25670c0ddb7a9afa106158074605a1016a2889655c20' \
--health-cmd='curl -f http://localhost:8080/health || exit 1' \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
${REGISTRY_URL}/${IMAGE_NAME}:${VERSION}
# Wait for container health # Force stop all littleshop containers (including orphans)
echo "Waiting for container to be healthy..." echo "Stopping all littleshop containers..."
docker stop \$(docker ps -q --filter "name=littleshop") 2>/dev/null || true
docker rm \$(docker ps -aq --filter "name=littleshop") 2>/dev/null || true
# Stop services with compose (removes networks)
echo "Stopping compose services..."
docker-compose down --remove-orphans || true
# Prune unused Docker networks to avoid conflicts
echo "Cleaning up Docker networks..."
docker network prune -f || true
# Start services with new image
echo "Starting services with new image..."
docker-compose up -d
# Wait for startup
echo "Waiting for services to start..."
sleep 30
# Health check
echo "Running health checks..."
for i in 1 2 3 4 5 6; do for i in 1 2 3 4 5 6; do
if echo "${DEPLOY_PASSWORD}" | sudo -S docker ps | grep -q "(healthy).*${CONTAINER_NAME}"; then if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then
echo "✅ Container is healthy" echo "✅ Deployment successful - health check passed"
break exit 0
fi fi
echo "Waiting for health check... attempt \$i/6" echo "Health check attempt \$i/6 failed, waiting..."
sleep 10 sleep 10
done done
# Test authentication redirect echo "❌ Health check failed after deployment"
echo "Testing authentication redirect..." docker logs littleshop-admin --tail 50
curl -I http://localhost:5100/Admin 2>/dev/null | head -15 exit 1
EOF
# Push to local registry for backup
echo "${DEPLOY_PASSWORD}" | sudo -S docker push ${REGISTRY_URL}/${IMAGE_NAME}:${VERSION} 2>/dev/null || true
echo "${DEPLOY_PASSWORD}" | sudo -S docker tag ${REGISTRY_URL}/${IMAGE_NAME}:${VERSION} ${REGISTRY_URL}/${IMAGE_NAME}:latest
echo "${DEPLOY_PASSWORD}" | sudo -S docker push ${REGISTRY_URL}/${IMAGE_NAME}:latest 2>/dev/null || true
# Health check API
if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then
echo "✅ Deployment successful - API health check passed"
else
echo "⚠️ API health check failed but container is running"
echo "${DEPLOY_PASSWORD}" | sudo -S docker logs ${CONTAINER_NAME} --tail 20
fi
# Cleanup
rm -f /tmp/littleshop.tar
echo "Deployment of version ${VERSION} complete!"
DEPLOY_SCRIPT
environment: environment:
name: production name: production
url: http://${DEPLOY_HOST}:5100 url: http://hq.lan
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"' - if: '$CI_COMMIT_BRANCH == "main"'
when: manual # Require manual approval for production when: on_success
- if: '$CI_COMMIT_TAG' - if: '$CI_COMMIT_TAG'
when: manual when: manual
tags: tags:
- docker - docker
# Rollback job rollback:vps:
rollback:hostinger:
stage: deploy stage: deploy
image: alpine:latest image: alpine:latest
before_script: before_script:
- apk add --no-cache openssh-client sshpass - apk add --no-cache openssh-client bash
- echo "$VPS_SSH_KEY_B64" | base64 -d > /tmp/deploy_key
- chmod 600 /tmp/deploy_key
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts
script: script:
- echo "Rolling back to previous version..." - echo "Rolling back to previous version"
- | - |
if [ -n "$HOSTINGER_SSH_KEY" ]; then ssh -i /tmp/deploy_key -p "$VPS_PORT" "$VPS_USER@$VPS_HOST" bash -s << EOF
echo "$HOSTINGER_SSH_KEY" | base64 -d > /tmp/hostinger_key
chmod 600 /tmp/hostinger_key
SSH_CMD="ssh -i /tmp/hostinger_key"
else
SSH_CMD="sshpass -p $DEPLOY_PASSWORD ssh"
fi
- |
$SSH_CMD -p ${DEPLOY_PORT} -o StrictHostKeyChecking=no ${DEPLOY_USER}@${DEPLOY_HOST} << ROLLBACK_SCRIPT
set -e set -e
cd /opt/littleshop
# Get previous image # Pull previous image
PREVIOUS_IMAGE=\$(echo "${DEPLOY_PASSWORD}" | sudo -S docker images ${REGISTRY_URL}/${IMAGE_NAME} --format "{{.Tag}}" | grep -v latest | head -2 | tail -1) docker tag localhost:5000/littleshop:previous localhost:5000/littleshop:latest
if [ -z "\$PREVIOUS_IMAGE" ]; then # Restart services
echo "❌ No previous image found for rollback" echo "Restarting with previous version..."
exit 1 docker-compose down
fi docker-compose up -d
echo "Rolling back to ${REGISTRY_URL}/${IMAGE_NAME}:\$PREVIOUS_IMAGE" # Health check
# Stop current container
echo "${DEPLOY_PASSWORD}" | sudo -S docker stop ${CONTAINER_NAME}
echo "${DEPLOY_PASSWORD}" | sudo -S docker rm ${CONTAINER_NAME}
# Start with previous image
echo "${DEPLOY_PASSWORD}" | sudo -S docker run -d \
--name ${CONTAINER_NAME} \
--restart unless-stopped \
-p 5100:8080 \
-v /var/opt/littleshop/data:/app/data \
-v /var/opt/littleshop/uploads:/app/wwwroot/uploads \
-e ASPNETCORE_ENVIRONMENT=Production \
-e WebPush__VapidPublicKey='BDJtQu7zV0H3KF4FkrZ8nPwP3YD_3cEz3hqJvQ6L_gvNpG8ANksQB-FZy2-PDmFAu6duiN4p3mkcNAGnN4YRbws' \
-e WebPush__VapidPrivateKey='Hm_ttUKUqoLn5R8WQP5O1SIGxm0kVJXMZGCPMD1tUDY' \
-e WebPush__VapidSubject='mailto:admin@littleshop.local' \
-e ConnectionStrings__DefaultConnection='Data Source=/app/data/littleshop-production.db' \
-e Jwt__Key='2D7B5FE9C4A3E1D8B6A947F2C8E5D3A1B9F7E4C2D8A6B3E9F1C7D5A2E8B4F6C9' \
-e Jwt__Audience='LittleShop-Production' \
-e Jwt__ExpiryInHours='24' \
-e Jwt__Issuer='LittleShop-Production' \
-e SilverPay__AllowUnsignedWebhooks='false' \
-e SilverPay__WebhookSecret='04126be1b2ca9a586aaf25670c0ddb7a9afa106158074605a1016a2889655c20' \
--health-cmd='curl -f http://localhost:8080/health || exit 1' \
--health-interval=30s \
--health-timeout=10s \
--health-retries=3 \
${REGISTRY_URL}/${IMAGE_NAME}:\$PREVIOUS_IMAGE
# Wait and check health
sleep 30 sleep 30
if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then if curl -f -s http://localhost:5100/api/catalog/products > /dev/null 2>&1; then
echo "✅ Rollback complete - service is healthy" echo "✅ Rollback complete"
exit 0
else else
echo "❌ Rollback health check failed" echo "❌ Rollback health check failed"
echo "${DEPLOY_PASSWORD}" | sudo -S docker logs ${CONTAINER_NAME} --tail 50 docker logs littleshop-admin --tail 50
exit 1 exit 1
fi fi
ROLLBACK_SCRIPT EOF
environment: environment:
name: production name: production
when: manual
rules: rules:
- if: '$CI_COMMIT_BRANCH == "main"'
- if: '$CI_COMMIT_TAG' - if: '$CI_COMMIT_TAG'
when: manual
tags: tags:
- docker - docker