DONE: update cicd for backend
Build Docker Image / build-backend (push) Successful in 30s

This commit is contained in:
2026-10-25 14:38:26 +08:00
parent bd75a0ed03
commit 3ff62ccec6
+90 -65
View File
@@ -12,11 +12,10 @@ on:
env:
BACKEND_IMAGE: git.koppkb.com/kopkb/my-kopkb-be
DEPLOY_DIR: /home/arrahn/Project
jobs:
deploy:
runs-on: host
runs-on: mykopkb-production
steps:
- name: Checkout repository
@@ -24,107 +23,133 @@ jobs:
with:
ref: ${{ inputs.image_tag }}
- name: Login to Docker registry
- name: Verify image exists in registry
run: |
set -e
echo "${{ secrets.REGISTRY_PASSWORD }}" | \
docker login git.koppkb.com \
-u "${{ secrets.REGISTRY_USERNAME }}" \
--password-stdin
- name: Verify images exist in registry
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
IMAGE="${BACKEND_IMAGE}:${IMAGE_TAG}"
IMAGE="${BACKEND_IMAGE}:${{ inputs.image_tag }}"
echo "Checking if image exists: ${IMAGE}"
if ! docker manifest inspect "${IMAGE}" > /dev/null 2>&1; then
echo "ERROR: Image ${IMAGE} does not exist in registry!"
exit 1
fi
docker manifest inspect "${IMAGE}" > /dev/null
echo "✓ ${IMAGE} found"
- name: Pull Docker images
- name: Deploy over SSH
env:
PROD_HOST: ${{ secrets.PROD_HOST }}
PROD_USER: ${{ secrets.PROD_USER }}
PROD_SSH_KEY: ${{ secrets.PROD_SSH_KEY }}
PROD_DEPLOY_DIR: ${{ secrets.PROD_DEPLOY_DIR }}
REGISTRY_USERNAME: ${{ secrets.REGISTRY_USERNAME }}
REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }}
IMAGE_TAG: ${{ inputs.image_tag }}
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
docker pull "${BACKEND_IMAGE}:${IMAGE_TAG}"
echo "✓ Image pulled successfully"
set -euo pipefail
- name: Sync compose file and deploy
run: |
set -e
IMAGE_TAG="${{ inputs.image_tag }}"
mkdir -p "${DEPLOY_DIR}"
cp docker/production/docker-compose.production.yml "${DEPLOY_DIR}/docker-compose.yml"
ENV_FILE=".env.production"
if [ ! -f "${ENV_FILE}" ]; then
echo "ERROR: ${ENV_FILE} is missing from the repository checkout"
if [ ! -f .env.production ]; then
echo "ERROR: .env.production is missing from the repository checkout"
exit 1
fi
cp "${ENV_FILE}" "${DEPLOY_DIR}/.env"
chmod 600 "${DEPLOY_DIR}/.env"
NGINX_CONF="$(pwd)/docker/production/nginx/nginx.conf"
if [ ! -f "${NGINX_CONF}" ]; then
echo "ERROR: nginx config not found at ${NGINX_CONF}"
if [ ! -f docker/production/nginx/nginx.conf ]; then
echo "ERROR: docker/production/nginx/nginx.conf is missing from the repository checkout"
exit 1
fi
cd "${DEPLOY_DIR}"
if ! command -v ssh >/dev/null 2>&1; then
apt-get update && apt-get install -y openssh-client
fi
export IMAGE_TAG
export NGINX_CONF
mkdir -p ~/.ssh
umask 077
# Gitea often stores a multiline key as one line. Prefer a base64
# secret (one line). A raw key that still contains BEGIN is accepted too.
if printf '%s' "$PROD_SSH_KEY" | grep -q -- '-----BEGIN'; then
printf '%b\n' "$PROD_SSH_KEY" | tr -d '\r' > ~/.ssh/id_ed25519
else
printf '%s' "$PROD_SSH_KEY" | tr -d '[:space:]' | base64 -d > ~/.ssh/id_ed25519
fi
chmod 600 ~/.ssh/id_ed25519
if ! ssh-keygen -y -f ~/.ssh/id_ed25519 >/dev/null; then
echo "ERROR: PROD_SSH_KEY is not a readable private key."
echo "On the runner, run: base64 -w0 ~/.ssh/mykopkb_prod"
echo "Put that single line in the PROD_SSH_KEY secret."
exit 1
fi
ssh-keyscan -H "$PROD_HOST" >> ~/.ssh/known_hosts
SSH=(ssh -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes "${PROD_USER}@${PROD_HOST}")
IMAGE="${BACKEND_IMAGE}:${IMAGE_TAG}"
NGINX_CONF="${PROD_DEPLOY_DIR}/nginx/nginx.conf"
"${SSH[@]}" "mkdir -p '${PROD_DEPLOY_DIR}/nginx'"
scp -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes \
docker/production/docker-compose.production.yml \
"${PROD_USER}@${PROD_HOST}:${PROD_DEPLOY_DIR}/docker-compose.yml"
scp -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes \
.env.production \
"${PROD_USER}@${PROD_HOST}:${PROD_DEPLOY_DIR}/.env"
scp -i ~/.ssh/id_ed25519 -o IdentitiesOnly=yes \
docker/production/nginx/nginx.conf \
"${PROD_USER}@${PROD_HOST}:${NGINX_CONF}"
"${SSH[@]}" "bash -s" << EOF
set -euo pipefail
echo "${REGISTRY_PASSWORD}" | docker login git.koppkb.com \
-u "${REGISTRY_USERNAME}" --password-stdin
echo "Checking if image exists: ${IMAGE}"
docker manifest inspect "${IMAGE}" > /dev/null
echo "✓ ${IMAGE} found"
echo "Deploying backend IMAGE=${IMAGE}"
chmod 600 "${PROD_DEPLOY_DIR}/.env"
docker network inspect mykopkb-production-network >/dev/null 2>&1 \
|| docker network create mykopkb-production-network
cd "${PROD_DEPLOY_DIR}"
export IMAGE_TAG="${IMAGE_TAG}"
export NGINX_CONF="${NGINX_CONF}"
docker rm -f mykopkb-be-production || true
docker compose -f docker-compose.yml pull backend
docker compose -f docker-compose.yml up -d backend
echo "✓ Deployed backend IMAGE_TAG=${IMAGE_TAG}"
- name: Verify deployment
run: |
set -e
cd "${DEPLOY_DIR}"
echo "Waiting for services to start..."
echo "Waiting for the backend to start..."
sleep 10
STATUS=$(docker compose -f docker-compose.yml ps --status running --format '{{.Name}}' backend 2>/dev/null || true)
if [ -z "$STATUS" ]; then
STATUS=\$(docker compose -f docker-compose.yml ps --status running --format '{{.Name}}' backend || true)
if [ -z "\$STATUS" ]; then
echo "ERROR: backend is not running"
docker compose -f docker-compose.yml ps
docker compose -f docker-compose.yml logs --tail=50 backend || true
exit 1
fi
echo "✓ backend is running (${STATUS})"
echo "✓ backend is running (\$STATUS)"
BE_CONTAINER=$(docker compose -f docker-compose.yml ps -q backend)
if docker exec "$BE_CONTAINER" test -f /var/www/.env; then
BE_CONTAINER=\$(docker compose -f docker-compose.yml ps -q backend)
if docker exec "\$BE_CONTAINER" test -f /var/www/.env; then
echo "✓ Backend .env file exists"
else
echo "WARNING: Backend .env file not found"
fi
API_PORT=$(grep -E '^API_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"' || true)
API_PORT=${API_PORT:-8080}
API_PORT=\$(grep -E '^API_PORT=' .env 2>/dev/null | cut -d= -f2- | tr -d '"' || true)
API_PORT=\${API_PORT:-8080}
check_health() {
NAME=$1
URL=$2
for i in 1 2 3 4 5 6; do
if curl -sf "$URL" > /dev/null; then
echo "✓ ${NAME} health check passed (${URL})"
return 0
if curl -sf "http://127.0.0.1:\${API_PORT}/health" > /dev/null; then
echo "✓ backend health check passed (http://127.0.0.1:\${API_PORT}/health)"
echo "✓ Deployed backend IMAGE_TAG=${IMAGE_TAG}"
exit 0
fi
echo "Waiting for ${NAME}... attempt ${i}/6"
echo "Waiting for backend... attempt \${i}/6"
sleep 5
done
echo "ERROR: ${NAME} health check failed (${URL})"
docker compose -f docker-compose.yml logs --tail=50 "${NAME}" || true
return 1
}
check_health "backend" "http://127.0.0.1:${API_PORT}/health"
echo "ERROR: backend health check failed (http://127.0.0.1:\${API_PORT}/health)"
docker compose -f docker-compose.yml logs --tail=50 backend || true
exit 1
EOF