diff --git a/.github/workflows/build-and-deploy-dev.yml b/.github/workflows/build-and-deploy-dev.yml new file mode 100644 index 0000000..8de7434 --- /dev/null +++ b/.github/workflows/build-and-deploy-dev.yml @@ -0,0 +1,67 @@ +name: Build and Deploy (Dev) + +on: + push: + branches: [main] + +permissions: + contents: read + packages: write + deployments: write + actions: read + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + outputs: + image_tag: ${{ steps.vars.outputs.image_tag }} + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set image tag + id: vars + run: echo "image_tag=main-${GITHUB_SHA::7}" >> $GITHUB_OUTPUT + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha,prefix=main- + type=raw,value=latest + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + file: docker/Dockerfile.prod + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + deploy: + needs: build-and-push + uses: ad-build-test/build-system-playbooks/.github/workflows/request-deployment.yml@main + with: + deploy_to_container_dev: true + tag: ${{ needs.build-and-push.outputs.image_tag }} + deployment_type: container + docker_network: squirrel-net + migration_command: alembic upgrade head + health_check_path: /docs + secrets: + database_url: ${{ secrets.DEV_DATABASE_URL }} + redis_url: ${{ secrets.DEV_REDIS_URL }} diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 0000000..4bc8fcb --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,45 @@ +name: Build Release Image + +on: + release: + types: [published] + +permissions: + contents: read + packages: write + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + + - name: Build and push + uses: docker/build-push-action@v5 + with: + context: . + file: docker/Dockerfile.prod + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml new file mode 100644 index 0000000..8239a2f --- /dev/null +++ b/.github/workflows/deploy-prod.yml @@ -0,0 +1,28 @@ +name: Deploy to Production + +on: + workflow_dispatch: + inputs: + image_tag: + description: 'Release tag to deploy (e.g., v1.2.0)' + required: true + type: string + +permissions: + deployments: write + contents: read + actions: read + +jobs: + deploy: + uses: ad-build-test/build-system-playbooks/.github/workflows/request-deployment.yml@main + with: + deploy_to_container_prod: true + tag: ${{ inputs.image_tag }} + deployment_type: container + docker_network: squirrel-net + migration_command: alembic upgrade head + health_check_path: /docs + secrets: + database_url: ${{ secrets.PROD_DATABASE_URL }} + redis_url: ${{ secrets.PROD_REDIS_URL }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..336f303 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,31 @@ +# [Required] +# Basic component information +repo: react-squirrel-backend +organization: ad-build-test +url: https://github.com/ad-build-test/react-squirrel-backend +description: test react-squirrel-backend + +# [Required] +# Continous integration +approvalRule: all +testingCriteria: all +issueTracker: github +jiraProjectKey: n/a + +# [Required] +# Type of deployment +# Types: [ioc, hla, tools, matlab, pydm, container] +deploymentType: container + +# [Optional] +# Build method for building the component +# Can be a simple command like 'make' +# build: + +# [Optional] +# Environments this app runs on +# environments: + +# [Optional] +# Directories and files needed to run application +# runtimeDependencies: diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..336f303 --- /dev/null +++ b/config.yaml @@ -0,0 +1,31 @@ +# [Required] +# Basic component information +repo: react-squirrel-backend +organization: ad-build-test +url: https://github.com/ad-build-test/react-squirrel-backend +description: test react-squirrel-backend + +# [Required] +# Continous integration +approvalRule: all +testingCriteria: all +issueTracker: github +jiraProjectKey: n/a + +# [Required] +# Type of deployment +# Types: [ioc, hla, tools, matlab, pydm, container] +deploymentType: container + +# [Optional] +# Build method for building the component +# Can be a simple command like 'make' +# build: + +# [Optional] +# Environments this app runs on +# environments: + +# [Optional] +# Directories and files needed to run application +# runtimeDependencies: diff --git a/docker/Dockerfile.prod b/docker/Dockerfile.prod new file mode 100644 index 0000000..c03b9a7 --- /dev/null +++ b/docker/Dockerfile.prod @@ -0,0 +1,43 @@ +# Multi-stage build for production +FROM python:3.11-slim AS builder + +WORKDIR /app + +# Install system build dependencies for PyEPICS and aioca +RUN apt-get update && apt-get install -y \ + libreadline-dev \ + gcc \ + g++ \ + make \ + && rm -rf /var/lib/apt/lists/* + +# Install Python dependencies +COPY requirements.txt . +RUN pip install --no-cache-dir -r requirements.txt + +# --- Production stage --- +FROM python:3.11-slim + +WORKDIR /app + +# Install only runtime dependencies +RUN apt-get update && apt-get install -y \ + libreadline8 \ + && rm -rf /var/lib/apt/lists/* + +# Copy installed packages from builder +COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages +COPY --from=builder /usr/local/bin /usr/local/bin + +# Copy application code +COPY app/ ./app/ +COPY alembic/ ./alembic/ +COPY alembic.ini . + +# Create non-root user +RUN useradd -m -r appuser && chown -R appuser:appuser /app +USER appuser + +EXPOSE 8000 + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]