Nomad stuff
Some checks failed
Build and Deploy LifeFAQ / build-image (push) Failing after 3m21s

This commit is contained in:
Henrik Jess Nielsen
2025-10-05 15:54:42 +02:00
parent 0747579dcf
commit f318440572
4 changed files with 145 additions and 53 deletions

View File

@@ -1,63 +1,150 @@
name: Build, Push, and Deploy to Nomad name: Build and Deploy LifeFAQ
on: on:
push: push:
branches: branches:
- main - main
workflow_dispatch:
jobs: jobs:
docker-nomad: build-image:
runs-on: self-hosted runs-on: debian-host
env:
PATH: /usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/sbin:/bin:/snap/bin
DOCKER_HOST: unix:///var/run/docker.sock
BUILDX_CONFIG: /tmp/buildx
steps: steps:
- name: Check out code - name: Checkout code
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Log in to Container Registry - name: System info
run: echo ${{ secrets.password }} | docker login registry.i80.dk -u ${{ secrets.username }} --password-stdin
- name: Build Docker Image
run: | run: |
COMMIT_HASH=$(git rev-parse --short HEAD) uname -a
docker build -t registry.i80.dk/gitea/lifefaq:latest -t registry.i80.dk/gitea/lifefaq:${COMMIT_HASH} . whoami
- name: Set up Docker Context for Buildx
- name: Push Docker Image id: buildx-context
run: | run: |
COMMIT_HASH=$(git rev-parse --short HEAD) export DOCKER_HOST=tcp://docker:2376/
echo "registry.i80.dk/gitea/lifefaq:latest" export DOCKER_TLS_VERIFY=0
echo "registry.i80.dk/gitea/lifefaq:${COMMIT_HASH}" docker context rm builders || true
docker push registry.i80.dk/gitea/lifefaq:${COMMIT_HASH} docker context create builders
docker push registry.i80.dk/gitea/lifefaq:latest
- name: Verify Docker
run: docker --version
- name: Validate Nomad Job - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
env: env:
NOMAD_ADDR: https://nomad.i80.dk PATH: /usr/bin:/usr/local/bin:/bin:/sbin:/usr/sbin
run: nomad job validate .gitea/workflows/nomad-job.hcl
- name: Stop old deployment - name: Log in to Docker Registry
run: |
echo "${{ secrets.HARBOR_ROBOT_TOKEN }}" | docker login registry.i80.dk -u "robot\$gitserver" --password-stdin
env: env:
NOMAD_ADDR: https://nomad.i80.dk PATH: /usr/bin:/usr/local/bin:/bin:/sbin:/usr/sbin
run: nomad job stop -purge -no-shutdown-delay lifefaq
continue-on-error: true
- name: Check for changes
id: changes
uses: dorny/paths-filter@v2
with:
filters: |
docker:
- 'Dockerfile'
- 'app/**'
- 'requirements.txt'
- name: Apply Nomad Job - name: Build and push Docker image
if: steps.changes.outputs.docker == 'true'
uses: docker/build-push-action@v5
env: env:
NOMAD_ADDR: https://nomad.i80.dk PATH: /usr/bin:/usr/local/bin:/bin:/sbin:/usr/sbin
run: nomad job run .gitea/workflows/nomad-job.hcl with:
context: .
file: ./Dockerfile
push: true
tags: |
registry.i80.dk/gitea/lifefaq:latest
- name: Update Nginx Configuration - name: Test container health
run: ssh runner@nomad sudo /opt/nginx_updater/venv/bin/python3 /opt/nginx_updater/nginx_updater.py lifefaq run: |
echo "=== Starting container for health check ==="
- name: Update Forwarder Configuration docker pull registry.i80.dk/gitea/lifefaq:latest
run: ssh runner@nomad sudo /opt/nginx_updater/venv/bin/python3 /opt/nginx_updater/update_forwarder.py --subdomain lifefaq
CONTAINER_ID=$(docker run -d \
-p 8000:8000 \
-e PORT=8000 \
-e APP_ENV=production \
--name lifefaq-test \
registry.i80.dk/gitea/lifefaq:latest)
# - name: Restart Nomad Job echo "Container started: ${CONTAINER_ID}"
# env:
# NOMAD_ADDR: https://nomad.i80.dk echo "Waiting for /health endpoint..."
# run: | SUCCESS=false
# nomad job stop lifefaq for i in {1..90}; do
# sleep 5 # Optional: Wait to ensure the old allocation is stopped if curl -f -s http://localhost:8000/health > /dev/null 2>&1; then
# nomad job run .gitea/workflows/nomad-job.hcl echo "✓ Health check passed after ${i} seconds"
curl -s http://localhost:8000/health | jq '.' || echo "Health endpoint returned OK"
SUCCESS=true
break
fi
echo "Attempt ${i}/90 - waiting..."
sleep 1
done
echo "=== Container Logs ==="
docker logs lifefaq-test
docker stop lifefaq-test
docker rm lifefaq-test
if [ "$SUCCESS" = false ]; then
echo "✗ Health check failed after 90 seconds"
exit 1
fi
echo "✓ Container health check passed - safe to deploy"
env:
PATH: /usr/bin:/usr/local/bin:/bin:/sbin:/usr/sbin
- name: Deploy to Nomad
run: |
nomad job validate lifefaq.nomad
nomad job run lifefaq.nomad
env:
NOMAD_ADDR: "https://nomad.i80.dk:4646"
- name: Wait for deployment
run: |
echo "Checking deployment status..."
nomad job status lifefaq
echo "=== Allocation Details ==="
nomad job allocs lifefaq
echo "=== Getting logs from allocations ==="
for alloc in $(nomad job allocs -all lifefaq | tail -n +2 | awk '{print $1}'); do
echo "Logs for allocation $alloc:"
timeout=250
SECONDS=0
until nomad alloc logs "$alloc" 2>/dev/null || [ $SECONDS -gt $timeout ]; do
echo "Waiting for allocation to start... ($SECONDS/$timeout seconds)"
sleep 5
done
[ $SECONDS -gt $timeout ] && echo "Timeout for $alloc"
echo "---"
done
env:
NOMAD_ADDR: "https://nomad.i80.dk:4646"
- name: Notify deployment status
run: |
echo "✅ Deployment completed!"
echo "LifeFAQ should be available at: https://lifefaq.i80.dk"
echo "Health check endpoint: https://lifefaq.i80.dk/health"

View File

@@ -1,20 +1,13 @@
# Base image with Python 3.11
FROM python:3.11-slim FROM python:3.11-slim
# Set the working directory in the container
WORKDIR /app WORKDIR /app
# Copy the requirements file to the working directory
COPY requirements.txt . COPY requirements.txt .
# Install Python dependencies
RUN pip install --no-cache-dir -r requirements.txt RUN pip install --no-cache-dir -r requirements.txt
# Copy the rest of the application code
COPY . . COPY . .
# Expose the port the FastAPI app runs on (default Uvicorn port) # Port will be set via environment variable
EXPOSE 9210 EXPOSE 8000
# Command to run the FastAPI application CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "${PORT:-8000}", "--workers", "1"]
CMD ["uvicorn", "app.main:app", "--proxy-headers", "--host", "0.0.0.0", "--port", "9210", "--workers", "1"]

9
app.py
View File

@@ -1,5 +1,12 @@
import os
import uvicorn import uvicorn
from app.main import app from app.main import app
if __name__ == "__main__": if __name__ == "__main__":
uvicorn.run("app.main:app", host="0.0.0.0", port=9210, reload=False) port = int(os.getenv("PORT", 8000))
uvicorn.run(
"app.main:app",
host="0.0.0.0",
port=port,
reload=False
)

View File

@@ -2,6 +2,7 @@ from fastapi import FastAPI
from contextlib import asynccontextmanager from contextlib import asynccontextmanager
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
import app
from app.controllers.route_to_web import RouteToWeb from app.controllers.route_to_web import RouteToWeb
from app.services.markdown_processor import MarkdownProcessor from app.services.markdown_processor import MarkdownProcessor
from app.services.metadata_processor import MetadataProcessor from app.services.metadata_processor import MetadataProcessor
@@ -68,6 +69,10 @@ class Application:
"""Return the FastAPI app instance.""" """Return the FastAPI app instance."""
return self.app return self.app
@app.get("/health")
async def health(self):
return {"status": "healthy"}
application = Application() application = Application()
app = application.get_app() app = application.get_app()