diff --git a/.github/workflows/container-deploy.yml b/.github/workflows/container-deploy.yml new file mode 100644 index 00000000..a01e2fee --- /dev/null +++ b/.github/workflows/container-deploy.yml @@ -0,0 +1,158 @@ +name: Container Image Deployment CI + +on: + push: + # Initially only doing production deploy + # branches: + # - main + # - deploy-* + tags: + - v*.*.* + +jobs: + deploy: + runs-on: ubuntu-latest + strategy: + matrix: + env: + - ${{ startsWith(github.ref, 'refs/tags/v') && 'off-auth-org' || 'off-auth-net' }} + environment: ${{ matrix.env }} + concurrency: ${{ matrix.env }} + steps: + - name: Set various variable for production deployment + if: matrix.env == 'off-auth-org' + run: | + echo "SSH_PROXY_HOST=off1.openfoodfacts.org" >> $GITHUB_ENV + echo "SSH_USERNAME=off" >> $GITHUB_ENV + echo "SSH_PROXY_USERNAME=off" >> $GITHUB_ENV + echo "SSH_HOST=pmg.openfoodfacts.org" >> $GITHUB_ENV + + echo "KEYCLOAK_BASE_URL=https://auth.openfoodfacts.org" >> $GITHUB_ENV + echo "KC_DB_URL_HOST=10.1.0.120" >> $GITHUB_ENV + echo "PRODUCT_OPENER_URL=https://world.openfoodfacts.org" >> $GITHUB_ENV + echo "REDIS_URL=10.1.0.122:6379" >> $GITHUB_ENV + echo "SMTP_SERVER=10.1.0.102" >> $GITHUB_ENV + + - name: Wait for container build workflow + uses: tomchv/wait-my-workflow@v1.1.0 + id: wait-build + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: build + ref: ${{ github.event.pull_request.head.sha || github.sha }} + intervalSeconds: 10 + timeoutSeconds: 600 # 10m + + - name: Do something if build fail + if: steps.wait-build.outputs.conclusion == 'failure' + run: echo fail && false # fail if build fail + + - name: Do something if build timeout + if: steps.wait-build.outputs.conclusion == 'timed_out' + run: echo Timeout && false # fail if build time out + + - name: Checkout git repository + uses: appleboy/ssh-action@master + with: + host: ${{ env.SSH_HOST }} + username: ${{ env.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + proxy_host: ${{ env.SSH_PROXY_HOST }} + proxy_username: ${{ env.SSH_PROXY_USERNAME }} + proxy_key: ${{ secrets.SSH_PRIVATE_KEY }} + script_stop: false + script: | + # Clone Git repository if not already there + [ ! -d '${{ matrix.env}}' ] && git clone --depth 1 https://github.com/${{ github.repository }} ${{ matrix.env }} --no-single-branch 2>&1 + + # Go to repository directory + cd ${{ matrix.env}} + + # Fetch newest commits (in case it wasn't freshly cloned) + git fetch --depth 1 + + # Checkout current commit SHA + git checkout -qf ${{ github.sha }} + + - name: Set environment variables + uses: appleboy/ssh-action@master + with: + host: ${{ env.SSH_HOST }} + username: ${{ env.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + proxy_host: ${{ env.SSH_PROXY_HOST }} + proxy_username: ${{ env.SSH_PROXY_USERNAME }} + proxy_key: ${{ secrets.SSH_PRIVATE_KEY }} + script_stop: false + script: | + # Go to repository directory + cd ${{ matrix.env}} + + # Set environment variables + echo "KC_BOOTSTRAP_ADMIN_USERNAME=root" > .env + echo "KC_BOOTSTRAP_ADMIN_PASSWORD=${{ secrets.KC_BOOTSTRAP_ADMIN_PASSWORD }}" >> .env + echo "KEYCLOAK_BASE_URL=${{ env.KEYCLOAK_BASE_URL }}" >> .env + echo "KEYCLOAK_REALM_NAME=open-products-facts" >> .env + echo "COMPOSE_PROJECT_NAME=openfoodfacts-auth" >> .env + echo "COMPOSE_PATH_SEPARATOR=," >> .env + echo "COMPOSE_FILE=docker-compose.yml,docker/prod.yml" >> .env + echo "COMPOSE_FILE=PG_BOOTSTRAP_USERNAME=bootstrap" >> .env + echo "PG_BOOTSTRAP_PASSWORD=${{ secrets.PG_BOOTSTRAP_PASSWORD }}" >> .env + echo "KC_DB_URL_HOST=${{ env.KC_DB_URL_HOST }}" >> .env + echo "KC_DB_USERNAME=keycloak" >> .env + echo "KC_DB_PASSWORD=${{ secrets.KC_DB_PASSWORD }}" >> .env + echo "PRODUCT_OPENER_OIDC_CLIENT_ID=ProductOpener" >> .env + echo "PRODUCT_OPENER_URL=${{ env.PRODUCT_OPENER_URL }}" >> .env + echo "PRODUCT_OPENER_OIDC_CLIENT_SECRET=${{ secrets.PRODUCT_OPENER_OIDC_CLIENT_SECRET }}" >> .env + echo "REDIS_URL=${{ env.REDIS_URL }}" >> .env + echo "SMTP_SERVER=${{ env.SMTP_SERVER }}" >> .env + echo "KEYCLOAK_HTTP_PORT=5600" >> .env + echo "KEYCLOAK_MANAGEMENT_PORT=5602" >> .env + echo "KEYCLOAK_STARTUP=prod" >> .env + + echo "KEYCLOAK_TAG=sha-${{ github.sha }}" >> .env + echo "RESTART_POLICY=always" >> .env + + - name: Create database and user + uses: appleboy/ssh-action@master + with: + host: ${{ env.SSH_HOST }} + username: ${{ env.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + proxy_host: ${{ env.SSH_PROXY_HOST }} + proxy_username: ${{ env.SSH_PROXY_USERNAME }} + proxy_key: ${{ secrets.SSH_PRIVATE_KEY }} + script_stop: false + script: | + cd ${{ matrix.env }} + make create_user_prod + + - name: Start services + uses: appleboy/ssh-action@master + with: + host: ${{ env.SSH_HOST }} + username: ${{ env.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + proxy_host: ${{ env.SSH_PROXY_HOST }} + proxy_username: ${{ env.SSH_PROXY_USERNAME }} + proxy_key: ${{ secrets.SSH_PRIVATE_KEY }} + script_stop: false + script: | + cd ${{ matrix.env }} + docker compose up --wait --wait-timeout 120 + + - name: Cleanup obsolete Docker objects + uses: appleboy/ssh-action@master + if: ${{ always() }} + with: + host: ${{ env.SSH_HOST }} + username: ${{ env.SSH_USERNAME }} + key: ${{ secrets.SSH_PRIVATE_KEY }} + proxy_host: ${{ env.SSH_PROXY_HOST }} + proxy_username: ${{ env.SSH_PROXY_USERNAME }} + proxy_key: ${{ secrets.SSH_PRIVATE_KEY }} + script_stop: false + script: | + cd ${{ matrix.env }} + make prune + diff --git a/Makefile b/Makefile index fce81afa..9d23241b 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,9 @@ down: hdown: docker compose down -v --remove-orphans +prune: + docker system prune -af + create_externals: docker volume create ${COMPOSE_PROJECT_NAME}_pgdata @@ -84,6 +87,13 @@ create_user: create_bootstrap -c "PGPASSWORD=${PG_BOOTSTRAP_PASSWORD} psql -h ${KC_DB_URL_HOST} -d postgres -U ${PG_BOOTSTRAP_USERNAME} -c \"create role ${KC_DB_USERNAME} with password '${KC_DB_PASSWORD}' login createdb\"; \ PGPASSWORD=${KC_DB_PASSWORD} psql -h ${KC_DB_URL_HOST} -d postgres -U ${KC_DB_USERNAME} -c \"create database ${KC_DB_USERNAME}\" || true " +# Create user / database in production PostgreSQL instance +create_user_prod: + @docker run --rm --entrypoint bin/bash postgres:16-alpine \ + -c "PGPASSWORD=${PG_BOOTSTRAP_PASSWORD} psql -h ${KC_DB_URL_HOST} -d postgres -U ${PG_BOOTSTRAP_USERNAME} -c \"create role ${KC_DB_USERNAME} with password '${KC_DB_PASSWORD}' login createdb\"; \ + PGPASSWORD=${KC_DB_PASSWORD} psql -h ${KC_DB_URL_HOST} -d postgres -U ${KC_DB_USERNAME} -c \"create database ${KC_DB_USERNAME}\" || true " + + # Called by other projects to start this project as a dependency run: run_deps COMPOSE_FILE=${COMPOSE_FILE_RUN} docker compose up -d diff --git a/docker/prod.yml b/docker/prod.yml new file mode 100644 index 00000000..315c99c8 --- /dev/null +++ b/docker/prod.yml @@ -0,0 +1,10 @@ +services: + keycloak: + environment: + - KC_DB=postgres + - KC_DB_URL_HOST + - KC_DB_USERNAME + - KC_DB_PASSWORD + ports: + - "${KEYCLOAK_EXPOSE}${KEYCLOAK_HTTP_PORT}:8080" + - "${KEYCLOAK_EXPOSE}${KEYCLOAK_MANAGEMENT_PORT}:9000"