Files
website-template/.gitea/workflows/ci.yml

209 lines
6.9 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: CI
on:
push:
branches:
- master
pull_request:
env:
IMAGE_NAME: ${{ vars.IMAGE_NAME }}
REGISTRY_LOCATION: ${{ vars.REGISTRY_LOCATION }}
REGISTRY_ORGANIZATION: ${{ vars.REGISTRY_ORGANIZATION }}
PORT: ${{ vars.PORT }}
TEST_PORT: ${{ vars.TEST_PORT }}
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
PROD_SERVER_HOST: ${{ secrets.PROD_SERVER_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
BUILD_NUMBER: build-${{ gitea.run_number }}
jobs:
lint:
name: ✅ Lint & Validate
runs-on: ubuntu-latest
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
- name: 🔧 Validate HTML
run: |
echo "Basic HTML validation"
test -f index.html
build:
name: Build & Push Docker Image
runs-on: ubuntu-latest
needs: lint
steps:
- name: 📥 Checkout repository
uses: actions/checkout@v4
- name: 🐋 Build Docker image
run: |
docker build \
-t $IMAGE_NAME:$BUILD_NUMBER \
-t $IMAGE_NAME:latest \
.
- name: Image info
run: docker images | grep $IMAGE_NAME
- name: 🔑 Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login $REGISTRY_LOCATION \
-u "$REGISTRY_USER" --password-stdin
- name: 🏷️ Build images
run: |
docker tag $IMAGE_NAME:latest $REGISTRY_LOCATION/$REGISTRY_ORGANIZATION/$IMAGE_NAME:latest
docker tag $IMAGE_NAME:$BUILD_NUMBER $REGISTRY_LOCATION/$REGISTRY_ORGANIZATION/$IMAGE_NAME:$BUILD_NUMBER
- name: 🚀 Push images
run: |
docker push $REGISTRY_LOCATION/$REGISTRY_ORGANIZATION/$IMAGE_NAME:latest
docker push $REGISTRY_LOCATION/$REGISTRY_ORGANIZATION/$IMAGE_NAME:$BUILD_NUMBER
deploy:
name: 🚀 Deploy image to prod
runs-on: ubuntu-latest
needs: build
steps:
- name: 🔑 Setup SSH
run: |
mkdir -p ~/.ssh
echo "$DEPLOY_SSH_KEY" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
ssh-keyscan -H $PROD_SERVER_HOST >> ~/.ssh/known_hosts
- name: 🗝️ Login to registry
run: |
echo "$REGISTRY_TOKEN" | docker login $REGISTRY_LOCATION \
-u "$REGISTRY_USER" --password-stdin
- name: 🔌 SSH into the prod server
run: |
ssh $DEPLOY_USER@$PROD_SERVER_HOST << 'EOF'
sleep 5
- name: 🚀 Deploy container to prod
run: |
set -e
NEW_IMAGE_NAME="$REGISTRY_LOCATION/$REGISTRY_ORGANIZATION/$IMAGE_NAME:$BUILD_NUMBER"
TEST_CONTAINER_NAME=test-$IMAGE_NAME
OLD_IMAGE_NAME=$(docker inspect $IMAGE_NAME --format='{{.Config.Image}}')
NEW_CONTAINER_IMAGE="$IMAGE_NAME:$BUILD_NUMBER"
echo "🏗️ Building functions"
# checks the health of the given container name $1
# returns "healthy" or "unhealthy"
is_container_healthy() {
for i in {1..15}; do
RETURN=$(docker inspect --format='{{.State.Health.Status}}' $1)
[ "$RETURN" = "healthy" ] && break
[ "$RETURN" = "unhealthy" ] && break
sleep 2
done
echo "$RETURN"
}
echo "🎣 Pulling image $NEW_IMAGE_NAME"
docker pull "$NEW_IMAGE_NAME"
echo "🧪 Test the new container health"
# if old test container is running then stop and remove it
if docker ps -a --format '{{.Names}}' | grep "^$TEST_CONTAINER_NAME$"; then
echo "Container ${TEST_CONTAINER_NAME} is running. Stopping and removing..."
docker stop $TEST_CONTAINER_NAME
docker rm $TEST_CONTAINER_NAME
fi
echo "Starting new test container"
docker run -d \
--name $TEST_CONTAINER_NAME \
--health-cmd="curl -f http://$PROD_SERVER_HOST:$TEST_PORT/health || exit 1" \
--health-interval=5s \
--health-retries=5 \
--health-timeout=2s \
--health-start-period=5s \
-p $TEST_PORT:80 \
"$NEW_CONTAINER_IMAGE"
TEST_CONTAINER_HEALTHCHECK=$(is_container_healthy $TEST_CONTAINER_NAME)
docker stop $TEST_CONTAINER_NAME
docker rm $TEST_CONTAINER_NAME
echo "🚚 Deploy the new image if healthy, otherwise rollback"
if [ "$TEST_CONTAINER_HEALTHCHECK" = "healthy" ]; then
echo "✅ Test Container is healthy - starting deployment"
# Stop previous prod running container if found
if [ -n "$OLD_IMAGE_NAME" ]; then
echo "Stopping previous prod running container"
docker stop $IMAGE_NAME
docker rm $IMAGE_NAME
fi
docker run -d \
--name $IMAGE_NAME \
--health-cmd="curl -f http://$PROD_SERVER_HOST:$PORT/health || exit 1" \
--health-interval=5s \
--health-retries=5 \
--health-timeout=2s \
--health-start-period=5s \
-p $PORT:80 \
"$NEW_CONTAINER_IMAGE"
PROD_CONTAINER_HEALTHCHECK=$(is_container_healthy $IMAGE_NAME)
if [ "$PROD_CONTAINER_HEALTHCHECK" != "healthy" ]; then
echo "❌ Deployment failed — rolling back"
docker logs $IMAGE_NAME
docker stop $IMAGE_NAME
docker rm -f $IMAGE_NAME
docker image rm $NEW_CONTAINER_IMAGE
if [ -n "$OLD_IMAGE_NAME" ]; then
docker run -d \
--name $IMAGE_NAME \
--health-cmd="curl -f http://$PROD_SERVER_HOST:$PORT/health || exit 1" \
--health-interval=5s \
--health-retries=5 \
--health-timeout=2s \
--health-start-period=5s \
-p $PORT:80 \
"$OLD_IMAGE_NAME"
if [["$(is_container_healthy $IMAGE_NAME)" == "healthy" ]]; then
echo "❌ Deployment failed — ✅ rollback successfull"
else
echo "❌ Deployment failed — ❌ rollback failed"
fi
exit 1
fi
echo "❌ Deployment failed — ❌ rollback not possible (no previous version was running)"
exit 1
fi
if [ -n "$OLD_IMAGE_NAME" ]; then
docker image rm $OLD_IMAGE_NAME
fi
echo "✅ Deployment successfull ($IMAGE_NAME)"
exit 0
else
docker image rm $NEW_CONTAINER_IMAGE
echo "❌ Deployment failed — ❤️ healthcheck failed on the test container"
exit 1
fi