diff --git a/.gitea/workflows/ci-cd.yml b/.gitea/workflows/ci-cd.yml index 5349b80..9e7a868 100644 --- a/.gitea/workflows/ci-cd.yml +++ b/.gitea/workflows/ci-cd.yml @@ -14,6 +14,10 @@ on: env: PYTHON_VERSION: "3.11" + REGISTRY_HOST: "registry.dev.nii-ecos.ru" + REGISTRY_NAMESPACE: "${{ github.repository_owner }}" + WEB_IMAGE: "state-corp-backend-web" + CELERY_IMAGE: "state-corp-backend-celery" jobs: lint: @@ -109,49 +113,12 @@ jobs: export PYTHONPATH="${PWD}/src:${PYTHONPATH:-}" .venv/bin/python -m pytest tests -q - build: - name: Build Docker Images + build_push: + name: Build and Push Dev Images runs-on: ubuntu-latest + timeout-minutes: 45 needs: [lint, test] - - steps: - - name: Checkout code - run: | - set -euo pipefail - REPO_URL=$(echo "${GITHUB_SERVER_URL}" | sed "s|://|://oauth2:${{ gitea.token }}@|") - BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME}}" - git clone --depth=1 --branch="${BRANCH}" "${REPO_URL}/${GITHUB_REPOSITORY}.git" . - git checkout "${GITHUB_SHA}" - - - name: Build web image - run: | - set -euo pipefail - BRANCH_TAG=$(echo "${GITHUB_REF_NAME}" | sed 's/\//-/g') - SHA_SHORT=$(echo "${GITHUB_SHA}" | cut -c1-7) - docker build \ - -f ./docker/Dockerfile \ - --target runtime-web \ - -t state_corp-web:${BRANCH_TAG} \ - -t state_corp-web:${BRANCH_TAG}-${SHA_SHORT} \ - . - - - name: Build celery image - run: | - set -euo pipefail - BRANCH_TAG=$(echo "${GITHUB_REF_NAME}" | sed 's/\//-/g') - SHA_SHORT=$(echo "${GITHUB_SHA}" | cut -c1-7) - docker build \ - -f ./docker/Dockerfile \ - --target runtime-celery \ - -t state_corp-celery:${BRANCH_TAG} \ - -t state_corp-celery:${BRANCH_TAG}-${SHA_SHORT} \ - . - - push: - name: Push to Gitea Registry - runs-on: ubuntu-latest - needs: [build] - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/dev' + if: github.event_name == 'push' && github.ref == 'refs/heads/dev' && !contains(github.event.head_commit.message, '#no_image') steps: - name: Checkout code @@ -164,46 +131,63 @@ jobs: - name: Build and push images env: - REGISTRY_USER: ${{ secrets.REGISTRY_USER }} - REGISTRY_PASSWORD: ${{ secrets.REGISTRY_TOKEN }} + REGISTRY_USER: ${{ secrets.REGISTRY_USERNAME }} + REGISTRY_PASSWORD: ${{ secrets.REGISTRY_PASSWORD }} run: | set -euo pipefail if [ -z "${REGISTRY_USER:-}" ] || [ -z "${REGISTRY_PASSWORD:-}" ]; then - echo "Registry credentials are not configured; skipping image push." - exit 0 + echo "Registry credentials are not configured" >&2 + exit 1 fi - curl -sL https://github.com/google/go-containerregistry/releases/download/v0.19.0/go-containerregistry_Linux_x86_64.tar.gz | tar xz crane - chmod +x crane + SHA_SHORT="$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)" + BUILD_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)" + REGISTRY="${REGISTRY_HOST}/${REGISTRY_NAMESPACE}" + WEB_REF="${REGISTRY}/${WEB_IMAGE}" + CELERY_REF="${REGISTRY}/${CELERY_IMAGE}" - BRANCH_TAG=$(echo "${GITHUB_REF_NAME}" | sed 's/\//-/g') - SHA_SHORT=$(echo "${GITHUB_SHA}" | cut -c1-7) - REGISTRY_HOST="10.10.0.10:3000" - REGISTRY="${REGISTRY_HOST}/${{ github.repository_owner }}" + echo "${REGISTRY_PASSWORD}" \ + | docker login "${REGISTRY_HOST}" \ + -u "${REGISTRY_USER}" \ + --password-stdin - echo "${REGISTRY_PASSWORD}" | ./crane auth login --insecure "${REGISTRY_HOST}" -u "${REGISTRY_USER}" --password-stdin - - docker build -f ./docker/Dockerfile --target runtime-web -t state_corp-web:local . - docker save state_corp-web:local -o /tmp/web.tar - ./crane push --insecure /tmp/web.tar "${REGISTRY}/state_corp-web:${BRANCH_TAG}" - ./crane push --insecure /tmp/web.tar "${REGISTRY}/state_corp-web:${BRANCH_TAG}-${SHA_SHORT}" - if [ "${GITHUB_REF_NAME}" = "dev" ]; then - ./crane push --insecure /tmp/web.tar "${REGISTRY}/state_corp-web:latest" + if ! docker buildx inspect state-corp-builder >/dev/null 2>&1; then + docker buildx create --name state-corp-builder --use + else + docker buildx use state-corp-builder fi + docker buildx inspect --bootstrap - docker build -f ./docker/Dockerfile --target runtime-celery -t state_corp-celery:local . - docker save state_corp-celery:local -o /tmp/celery.tar - ./crane push --insecure /tmp/celery.tar "${REGISTRY}/state_corp-celery:${BRANCH_TAG}" - ./crane push --insecure /tmp/celery.tar "${REGISTRY}/state_corp-celery:${BRANCH_TAG}-${SHA_SHORT}" - if [ "${GITHUB_REF_NAME}" = "dev" ]; then - ./crane push --insecure /tmp/celery.tar "${REGISTRY}/state_corp-celery:latest" - fi + docker buildx build \ + -f ./docker/Dockerfile \ + --target runtime-web \ + --build-arg INSTALL_DEV=false \ + --label "org.opencontainers.image.revision=${GITHUB_SHA}" \ + --label "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \ + --label "org.opencontainers.image.created=${BUILD_TIME}" \ + --tag "${WEB_REF}:dev-${SHA_SHORT}" \ + --tag "${WEB_REF}:dev" \ + --push \ + . - deploy: - name: Deploy to Server + docker buildx build \ + -f ./docker/Dockerfile \ + --target runtime-celery \ + --build-arg INSTALL_DEV=false \ + --label "org.opencontainers.image.revision=${GITHUB_SHA}" \ + --label "org.opencontainers.image.source=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" \ + --label "org.opencontainers.image.created=${BUILD_TIME}" \ + --tag "${CELERY_REF}:dev-${SHA_SHORT}" \ + --tag "${CELERY_REF}:dev" \ + --push \ + . + + deploy_dev: + name: Deploy Dev via Compose runs-on: ubuntu-latest - needs: [push] - if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/dev' + timeout-minutes: 5 + needs: [build_push] + if: needs.build_push.result == 'success' steps: - name: Checkout code @@ -214,38 +198,40 @@ jobs: git clone --depth=1 --branch="${BRANCH}" "${REPO_URL}/${GITHUB_REPOSITORY}.git" . git checkout "${GITHUB_SHA}" - - name: Deploy via SSH + - name: Deploy prebuilt images via SSH env: DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} DEPLOY_USER: ${{ secrets.DEPLOY_USER }} DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} - REGISTRY_USER: ${{ secrets.REGISTRY_USER }} - REGISTRY_PASSWORD: ${{ secrets.REGISTRY_TOKEN }} + REGISTRY_HOST: ${{ secrets.REGISTRY_HOST }} + HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }} run: | set -euo pipefail - if [ -z "${DEPLOY_HOST:-}" ] || [ -z "${DEPLOY_USER:-}" ] || [ -z "${DEPLOY_SSH_KEY:-}" ] || [ -z "${REGISTRY_USER:-}" ] || [ -z "${REGISTRY_PASSWORD:-}" ]; then - echo "Deploy credentials are not configured; skipping deploy." + + if [ "${GITHUB_REF}" != "refs/heads/dev" ]; then + echo "Skip dev deploy for ${GITHUB_REF}" exit 0 fi - BRANCH_TAG=$(echo "${GITHUB_REF_NAME}" | sed 's/\//-/g') + case "${HEAD_COMMIT_MESSAGE:-}" in + *"#no_deploy"* | *"#no_image"*) + echo "Skip dev deploy because commit message disables deploy or image build" + exit 0 + ;; + esac + short_sha="$(printf '%s' "${GITHUB_SHA}" | cut -c1-7)" + image_tag="dev-${short_sha}" mkdir -p ~/.ssh - echo "${DEPLOY_SSH_KEY}" | base64 -d > ~/.ssh/deploy_key - chmod 600 ~/.ssh/deploy_key + printf '%s' "${DEPLOY_SSH_KEY}" | base64 -d > ~/.ssh/ecos_deploy_key + chmod 0600 ~/.ssh/ecos_deploy_key ssh-keyscan -H "${DEPLOY_HOST}" >> ~/.ssh/known_hosts 2>/dev/null - - scp -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no docker-compose.prod.yml "${DEPLOY_USER}@${DEPLOY_HOST}:/opt/state-corp-backend/" - - ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=no "${DEPLOY_USER}@${DEPLOY_HOST}" " - set -euo pipefail - cd /opt/state-corp-backend - echo '${REGISTRY_PASSWORD}' | docker login --username '${REGISTRY_USER}' --password-stdin 10.10.0.10:3000 - REGISTRY=10.10.0.10:3000/${{ github.repository_owner }} - export WEB_IMAGE=\${REGISTRY}/state_corp-web:${BRANCH_TAG} - export CELERY_IMAGE=\${REGISTRY}/state_corp-celery:${BRANCH_TAG} - docker compose --env-file .env.prod -f docker-compose.prod.yml pull web celery_worker celery_beat - docker compose --env-file .env.prod -f docker-compose.prod.yml down --remove-orphans || true - docker compose --env-file .env.prod -f docker-compose.prod.yml up -d - docker image prune -f - " + tmp_current="$(mktemp)" + ssh -i ~/.ssh/ecos_deploy_key "${DEPLOY_USER}@${DEPLOY_HOST}" 'cat /opt/ecos-dev/releases/current.env' > "${tmp_current}" + grep -v '^STATE_CORP_BACKEND_' "${tmp_current}" > "${tmp_current}.new" + cat >> "${tmp_current}.new" < /opt/ecos-dev/releases/current.env && rm -f /tmp/current.env && /opt/ecos-dev/deploy.sh state-corp-backend'