diff --git a/.github/workflows/prod.yml b/.github/workflows/prod.yml new file mode 100644 index 0000000..c02c0bc --- /dev/null +++ b/.github/workflows/prod.yml @@ -0,0 +1,142 @@ +--- +name: Prod + +on: + release: + types: + - released + - prereleased + - deploy/gcp + +jobs: + build: + outputs: + image: ${{ steps.export.outputs.image }} + tag: ${{ steps.export.outputs.tag }} + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: staging + + - name: Install (Buildx) + uses: docker/setup-buildx-action@v3 + + - name: Login (GCP) + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.CREDENTIALS_JSON }} + + - name: Install (Gcloud) + uses: google-github-actions/setup-gcloud@v1 + with: + project_id: crane-cloud-274413 + install_components: "gke-gcloud-auth-plugin" + + - name: Login (GCR) + run: gcloud auth configure-docker + + - id: meta + name: Tag + uses: docker/metadata-action@v3 + with: + flavor: | + latest=true + images: gcr.io/crane-cloud-274413/database-api + tags: | + type=ref,event=branch + type=ref,event=pr + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha + + - name: Build + uses: docker/build-push-action@v2 + with: + cache-from: type=gha + cache-to: type=gha,mode=max + context: . + file: docker/prod/Dockerfile + labels: ${{ steps.meta.outputs.labels }} + push: true + tags: ${{ steps.meta.outputs.tags }} + + - id: export + name: Export + uses: actions/github-script@v5 + with: + script: | + const metadata = JSON.parse(`${{ steps.meta.outputs.json }}`) + const fullUrl = metadata.tags.find((t) => t.includes(':sha-')) + if (fullUrl == null) { + core.error('Unable to find sha tag of image') + } else { + const tag = fullUrl.split(':')[1] + core.setOutput('image', fullUrl) + core.setOutput('tag', tag) + } + + Production: + name: Deploy (Production) + + needs: + - build + + runs-on: ubuntu-latest + + env: + namespace: cranecloud-prod + + steps: + - name: Clone + uses: actions/checkout@v2 + + - name: Login (GCP) + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.CREDENTIALS_JSON }} + + - name: Install (Gcloud) + uses: google-github-actions/setup-gcloud@v1 + with: + project_id: crane-cloud-274413 + install_components: "gke-gcloud-auth-plugin" + + - name: Login (Kubernetes Cluster) + uses: google-github-actions/get-gke-credentials@v1 + with: + cluster_name: staging-cluster + location: us-central1-a + project_id: crane-cloud-274413 + + - name: Add Repo (cranecloud) + run: | + helm repo add cranecloud https://crane-cloud.github.io/helm-charts/ + + - name: Helm Release + run: | + helm upgrade --install \ + database-api cranecloud/cranecloud \ + --values helm/values.prod.yaml \ + --namespace $namespace \ + --set image.tag="${{ needs.build.outputs.tag }}" \ + --set environment.DATABASE_URI="${{ secrets.PRODUCTION_DATABASE_URI }}" \ + --set environment.JWT_SALT="${{ secrets.PRODUCTION_JWT_SALT }}" \ + --set environment.ACTIVITY_LOGGER_URL="${{ secrets.PRODUCTION_ACTIVITY_LOGGER_URL }}" \ + --set environment.ADMIN_MYSQL_USER="${{ secrets.PRODUCTION_ADMIN_MYSQL_USER }}" \ + --set environment.ADMIN_MYSQL_PASSWORD="${{ secrets.PRODUCTION_ADMIN_MYSQL_PASSWORD }}" \ + --set environment.ADMIN_MYSQL_HOST="${{ secrets.PRODUCTION_ADMIN_MYSQL_HOST }}" \ + --set environment.ADMIN_MYSQL_PORT="${{ secrets.PRODUCTION_ADMIN_MYSQL_PORT }}" \ + --set environment.ADMIN_PSQL_USER="${{ secrets.PRODUCTION_ADMIN_PSQL_USER }}" \ + --set environment.ADMIN_PSQL_PASSWORD="${{ secrets.PRODUCTION_ADMIN_PSQL_PASSWORD }}" \ + --set environment.ADMIN_PSQL_HOST="${{ secrets.PRODUCTION_ADMIN_PSQL_HOST }}" \ + --set environment.ADMIN_PSQL_PORT="${{ secrets.PRODUCTION_ADMIN_PSQL_PORT }}" \ + --set environment.MAIL_PASSWORD="${{ secrets.PRODUCTION_MAIL_PASSWORD }}" \ + --timeout=300s + + - name: Monitor Rollout + run: | + kubectl rollout status deployment/database-api --timeout=300s --namespace $namespace diff --git a/.github/workflows/staging.yaml b/.github/workflows/staging.yaml index 26915c3..9d71996 100644 --- a/.github/workflows/staging.yaml +++ b/.github/workflows/staging.yaml @@ -5,6 +5,7 @@ on: push: branches: - develop + - deploy/gcp workflow_dispatch: @@ -20,10 +21,10 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Install (Buildx) - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v2 @@ -44,7 +45,7 @@ jobs: type=sha - name: Build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: cache-from: type=gha cache-to: type=gha,mode=max @@ -56,7 +57,7 @@ jobs: - id: export name: Export - uses: actions/github-script@v5 + uses: actions/github-script@v7 with: script: | const metadata = JSON.parse(`${{ steps.meta.outputs.json }}`) @@ -73,25 +74,47 @@ jobs: name: Deploy (Staging) needs: - - Build + - build runs-on: ubuntu-latest env: - namespace: cranecloud-microservice + namespace: cranecloud image: cranecloud/database-api steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 - - uses: azure/k8s-set-context@v1 + # - uses: azure/k8s-set-context@v1 + # with: + # kubeconfig: ${{ secrets.RENU_KUBECONFIG}} + + - name: Login (GCP) + uses: google-github-actions/auth@v2 + with: + credentials_json: ${{ secrets.CREDENTIALS_JSON }} + + - name: Install (Gcloud) + uses: google-github-actions/setup-gcloud@v2 with: - kubeconfig: ${{ secrets.RENU_KUBECONFIG}} + project_id: crane-cloud-274413 + install_components: "gke-gcloud-auth-plugin" + + - name: Login (Kubernetes Cluster) + uses: google-github-actions/get-gke-credentials@v2 + with: + cluster_name: staging-cluster + location: us-central1-a + project_id: crane-cloud-274413 + + - name: Add Repo (cranecloud) + run: | + helm repo add cranecloud https://crane-cloud.github.io/helm-charts/ - name: Helm Release run: | helm upgrade --install \ - database-api ./helm/chart \ + database-api cranecloud/cranecloud \ --values helm/values.staging.yaml \ --namespace $namespace \ --set image.tag="${{ needs.build.outputs.tag }}" \ @@ -106,6 +129,7 @@ jobs: --set environment.ADMIN_PSQL_PASSWORD="${{ secrets.STAGING_ADMIN_PSQL_PASSWORD }}" \ --set environment.ADMIN_PSQL_HOST="${{ secrets.STAGING_ADMIN_PSQL_HOST }}" \ --set environment.ADMIN_PSQL_PORT="${{ secrets.STAGING_ADMIN_PSQL_PORT }}" \ + --set environment.MAIL_PASSWORD="${{ secrets.MAIL_PASSWORD }}" \ --timeout=300s - name: Monitor Rollout diff --git a/helm/chart/.helmignore b/helm/chart/.helmignore deleted file mode 100644 index 0e8a0eb..0000000 --- a/helm/chart/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/helm/chart/Chart.yaml b/helm/chart/Chart.yaml deleted file mode 100644 index 2ac2414..0000000 --- a/helm/chart/Chart.yaml +++ /dev/null @@ -1,23 +0,0 @@ -apiVersion: v2 -name: cranecloud -description: A Helm chart for cranecloud applications - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.4 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. Versions are not expected to -# follow Semantic Versioning. They should reflect the version the application is using. -appVersion: 1.16.0 diff --git a/helm/chart/templates/_helpers.tpl b/helm/chart/templates/_helpers.tpl deleted file mode 100644 index 6f379e7..0000000 --- a/helm/chart/templates/_helpers.tpl +++ /dev/null @@ -1,47 +0,0 @@ -{{/* vim: set filetype=mustache: */}} -{{/* -Expand the name of the chart. -*/}} -{{- define "cranecloud.name" -}} -{{- default .Release.Name .Values.nameOverride .Chart.Name | trunc 63 | trimSuffix "-" }} -{{- end }} - - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "cranecloud.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "cranecloud.labels" -}} -helm.sh/chart: {{ include "cranecloud.chart" . }} -{{ include "cranecloud.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "cranecloud.selectorLabels" -}} -app: {{ include "cranecloud.name" . }} -app.kubernetes.io/name: {{ include "cranecloud.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "cranecloud.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "cranecloud.name" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} diff --git a/helm/chart/templates/celery-deployment.yaml b/helm/chart/templates/celery-deployment.yaml deleted file mode 100644 index 0f4a067..0000000 --- a/helm/chart/templates/celery-deployment.yaml +++ /dev/null @@ -1,54 +0,0 @@ -{{- if .Values.celery.create -}} -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "cranecloud.name" . }}-celery - labels: - {{- include "cranecloud.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.celery.replicaCount }} - selector: - matchLabels: - {{- include "cranecloud.selectorLabels" . | nindent 6 }} - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "cranecloud.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "cranecloud.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ include "cranecloud.name" . }}-celery - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - command: {{ .Values.celery.command | toYaml | nindent 12}} - env: - - name: test - value: test - {{- range $key, $value := .Values.environment }} - - name: {{ $key }} - value: {{ $value | quote }} - {{- end }} - ports: - - name: celery-worker - containerPort: {{ .Values.celery.port }} - protocol: TCP - resources: - {{- toYaml .Values.resources | nindent 12 }} -{{- end }} diff --git a/helm/chart/templates/deployment.yaml b/helm/chart/templates/deployment.yaml deleted file mode 100644 index fecab82..0000000 --- a/helm/chart/templates/deployment.yaml +++ /dev/null @@ -1,76 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "cranecloud.name" . }} - labels: - {{- include "cranecloud.labels" . | nindent 4 }} -spec: - replicas: {{ .Values.replicaCount }} - selector: - matchLabels: - {{- include "cranecloud.selectorLabels" . | nindent 6 }} - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 25% - type: RollingUpdate - template: - metadata: - {{- with .Values.podAnnotations }} - annotations: - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "cranecloud.selectorLabels" . | nindent 8 }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "cranecloud.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - containers: - - name: {{ include "cranecloud.name" . }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - env: - {{- range $key, $value := .Values.environment }} - - name: {{ $key }} - value: {{ $value | quote }} - {{- end }} - - ports: - - name: backend-api - containerPort: 8000 - protocol: TCP - resources: - {{- toYaml .Values.resources | nindent 12 }} - - name: nginx - image: nginx:1.21.6 - imagePullPolicy: IfNotPresent - ports: - - name: http - containerPort: 80 - volumeMounts: - - name: nginx-proxy-config - mountPath: /etc/nginx/conf.d/default.conf - subPath: nginx.conf - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - volumes: - - name: nginx-proxy-config - configMap: - name: {{ .Release.Name }}-nginx-configmap \ No newline at end of file diff --git a/helm/chart/templates/nginx-configmap.yaml b/helm/chart/templates/nginx-configmap.yaml deleted file mode 100644 index cd42607..0000000 --- a/helm/chart/templates/nginx-configmap.yaml +++ /dev/null @@ -1,7 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ .Release.Name }}-nginx-configmap -data: - nginx.conf: |- -{{ tpl .Values.nginxConf . | indent 4 }} \ No newline at end of file diff --git a/helm/chart/templates/service.yaml b/helm/chart/templates/service.yaml deleted file mode 100644 index a1dde64..0000000 --- a/helm/chart/templates/service.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "cranecloud.name" . }} - labels: - {{- include "cranecloud.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - selector: - {{- include "cranecloud.selectorLabels" . | nindent 4 }} diff --git a/helm/chart/templates/serviceaccount.yaml b/helm/chart/templates/serviceaccount.yaml deleted file mode 100644 index f59da51..0000000 --- a/helm/chart/templates/serviceaccount.yaml +++ /dev/null @@ -1,12 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "cranecloud.serviceAccountName" . }} - labels: - {{- include "cranecloud.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -{{- end }} diff --git a/helm/chart/values.yaml b/helm/chart/values.yaml deleted file mode 100644 index 3813002..0000000 --- a/helm/chart/values.yaml +++ /dev/null @@ -1,87 +0,0 @@ -# Default values for cranecloud-backend. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - -image: - repository: gcr.io/crane-cloud-274413/cranecloud-backend - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: latest - -imagePullSecrets: [] -nameOverride: "cranecloud" - -serviceAccount: - # Specifies whether a service account should be created - create: false - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the name template - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -service: - type: ClusterIP - port: 80 - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -autoscaling: - enabled: false - minReplicas: 1 - maxReplicas: 100 - targetCPUUtilizationPercentage: 80 - # targetMemoryUtilizationPercentage: 80 - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -nginxConf: - server { - listen 80; - server_name localhost; - - location / { - proxy_pass http://localhost:5000/; - proxy_set_header Host "localhost"; - } - } - -environment: - APP: "test-app" - - -celery: - create: false - command: - - "python" - - "run" - port: 5002 \ No newline at end of file diff --git a/helm/values.prod.yaml b/helm/values.prod.yaml new file mode 100644 index 0000000..6c6f260 --- /dev/null +++ b/helm/values.prod.yaml @@ -0,0 +1,52 @@ +replicaCount: 1 + +image: + repository: gcr.io/crane-cloud-274413/database-api + pullPolicy: Always + tag: ${{ DOCKER_IMAGE_TAG }} + +nameOverride: "database-api" + +service: + type: NodePort + port: 80 + +nginxConf: + server { + listen 80; + + location / { + proxy_pass http://localhost:8000/; + } + } + +port: 8000 + +environment: + FASTAPI_ENV: production + DATABASE_URI: ${{ DATABASE_URI }} + JWT_SALT: ${{ JWT_SALT }} + ACTIVITY_LOGGER_URL: ${{ ACTIVITY_LOGGER_URL }} + ADMIN_MYSQL_USER: ${{ ADMIN_MYSQL_USER }} + ADMIN_MYSQL_PASSWORD: ${{ ADMIN_MYSQL_PASSWORD }} + ADMIN_MYSQL_HOST: ${{ ADMIN_MYSQL_HOST }} + ADMIN_MYSQL_PORT: ${{ ADMIN_MYSQL_PORT }} + ADMIN_PSQL_USER: ${{ ADMIN_PSQL_USER }} + ADMIN_PSQL_PASSWORD: ${{ ADMIN_PSQL_PASSWORD }} + ADMIN_PSQL_HOST: ${{ ADMIN_PSQL_HOST }} + ADMIN_PSQL_PORT: ${{ ADMIN_PSQL_PORT }} + MAIL_PASSWORD: ${{ MAIL_PASSWORD }} + MAIL_USERNAME: no-reply@cranecloud.io + + +celery: + create: true + command: + - "poetry" + - "run" + - "celery" + - "-A" + - "main.celery" + - "worker" + - "--loglevel=info" + port: 5001 \ No newline at end of file diff --git a/helm/values.staging.yaml b/helm/values.staging.yaml index 93d5b8d..7d4d091 100644 --- a/helm/values.staging.yaml +++ b/helm/values.staging.yaml @@ -5,46 +5,12 @@ image: pullPolicy: Always tag: ${{ DOCKER_IMAGE_TAG }} -imagePullSecrets: [] - nameOverride: "database-api" -serviceAccount: - create: false - annotations: {} - name: "" - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - service: type: NodePort port: 80 -resources: {} - # limits: - # cpu: 512m - # memory: 512Mi - # requests: - # cpu: 512m - # memory: 512Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} - nginxConf: server { listen 80; @@ -54,6 +20,8 @@ nginxConf: } } +port: 8000 + environment: FASTAPI_ENV: production DATABASE_URI: ${{ DATABASE_URI }} @@ -67,8 +35,18 @@ environment: ADMIN_PSQL_PASSWORD: ${{ ADMIN_PSQL_PASSWORD }} ADMIN_PSQL_HOST: ${{ ADMIN_PSQL_HOST }} ADMIN_PSQL_PORT: ${{ ADMIN_PSQL_PORT }} + MAIL_PASSWORD: ${{ MAIL_PASSWORD }} + MAIL_USERNAME: no-reply@cranecloud.io - celery: - create: false + create: true + command: + - "poetry" + - "run" + - "celery" + - "-A" + - "main.celery" + - "worker" + - "--loglevel=info" + port: 5001 \ No newline at end of file diff --git a/newrelic.ini b/newrelic.ini new file mode 100644 index 0000000..f5fb528 --- /dev/null +++ b/newrelic.ini @@ -0,0 +1,209 @@ +# --------------------------------------------------------------------------- + +# +# This file configures the New Relic Python Agent. +# +# The path to the configuration file should be supplied to the function +# newrelic.agent.initialize() when the agent is being initialized. +# +# The configuration file follows a structure similar to what you would +# find for Microsoft Windows INI files. For further information on the +# configuration file format see the Python ConfigParser documentation at: +# +# http://docs.python.org/library/configparser.html +# +# For further discussion on the behaviour of the Python agent that can +# be configured via this configuration file see: +# +# http://newrelic.com/docs/python/python-agent-configuration +# + +# --------------------------------------------------------------------------- + +# Here are the settings that are common to all environments. + +[newrelic] + +# You must specify the license key associated with your New +# Relic account. This key binds the Python Agent's data to your +# account in the New Relic service. + + +# The application name. Set this to be the name of your +# application as you would like it to show up in New Relic UI. +# The UI will then auto-map instances of your application into a +# entry on your home dashboard page. + + +# New Relic offers distributed tracing for monitoring and analyzing modern +# distributed systems.Enable distributed tracing. +distributed_tracing.enabled = true + +# When "true", the agent collects performance data about your +# application and reports this data to the New Relic UI at +# newrelic.com. This global switch is normally overridden for +# each environment below. +monitor_mode = true + +# Sets the name of a file to log agent messages to. Useful for +# debugging any issues with the agent. This is not set by +# default as it is not known in advance what user your web +# application processes will run as and where they have +# permission to write to. Whatever you set this to you must +# ensure that the permissions for the containing directory and +# the file itself are correct, and that the user that your web +# application runs as can write to the file. If not able to +# write out a log file, it is also possible to say "stderr" and +# output to standard error output. This would normally result in +# output appearing in your web server log. +#log_file = /tmp/newrelic-python-agent.log + +# Sets the level of detail of messages sent to the log file, if +# a log file location has been provided. Possible values, in +# increasing order of detail, are: "critical", "error", "warning", +# "info" and "debug". When reporting any agent issues to New +# Relic technical support, the most useful setting for the +# support engineers is "debug". However, this can generate a lot +# of information very quickly, so it is best not to keep the +# agent at this level for longer than it takes to reproduce the +# problem you are experiencing. +log_level = info + +# The Python Agent communicates with the New Relic service using +# SSL by default. Note that this does result in an increase in +# CPU overhead, over and above what would occur for a non SSL +# connection, to perform the encryption involved in the SSL +# communication. This work is though done in a distinct thread +# to those handling your web requests, so it should not impact +# response times. You can if you wish revert to using a non SSL +# connection, but this will result in information being sent +# over a plain socket connection and will not be as secure. +ssl = true + +# High Security Mode enforces certain security settings, and +# prevents them from being overridden, so that no sensitive data +# is sent to New Relic. Enabling High Security Mode means that +# SSL is turned on, request parameters are not collected, and SQL +# can not be sent to New Relic in its raw form. To activate High +# Security Mode, it must be set to 'true' in this local .ini +# configuration file AND be set to 'true' in the server-side +# configuration in the New Relic user interface. For details, see +# https://docs.newrelic.com/docs/subscriptions/high-security +high_security = false + +# The Python Agent will attempt to connect directly to the New +# Relic service. If there is an intermediate firewall between +# your host and the New Relic service that requires you to use a +# HTTP proxy, then you should set both the "proxy_host" and +# "proxy_port" settings to the required values for the HTTP +# proxy. The "proxy_user" and "proxy_pass" settings should +# additionally be set if proxy authentication is implemented by +# the HTTP proxy. The "proxy_scheme" setting dictates what +# protocol scheme is used in talking to the HTTP proxy. This +# would normally always be set as "http" which will result in the +# agent then using a SSL tunnel through the HTTP proxy for end to +# end encryption. +# proxy_scheme = http +# proxy_host = hostname +# proxy_port = 8080 +# proxy_user = +# proxy_pass = + +# Capturing request parameters is off by default. To enable the +# capturing of request parameters, first ensure that the setting +# "attributes.enabled" is set to "true" (the default value), and +# then add "request.parameters.*" to the "attributes.include" +# setting. For details about attributes configuration, please +# consult the documentation. +# attributes.include = request.parameters.* + +# The transaction tracer captures deep information about slow +# transactions and sends this to the UI on a periodic basis. The +# transaction tracer is enabled by default. Set this to "false" +# to turn it off. +transaction_tracer.enabled = true + +# Threshold in seconds for when to collect a transaction trace. +# When the response time of a controller action exceeds this +# threshold, a transaction trace will be recorded and sent to +# the UI. Valid values are any positive float value, or (default) +# "apdex_f", which will use the threshold for a dissatisfying +# Apdex controller action - four times the Apdex T value. +transaction_tracer.transaction_threshold = apdex_f + +# When the transaction tracer is on, SQL statements can +# optionally be recorded. The recorder has three modes, "off" +# which sends no SQL, "raw" which sends the SQL statement in its +# original form, and "obfuscated", which strips out numeric and +# string literals. +transaction_tracer.record_sql = obfuscated + +# Threshold in seconds for when to collect stack trace for a SQL +# call. In other words, when SQL statements exceed this +# threshold, then capture and send to the UI the current stack +# trace. This is helpful for pinpointing where long SQL calls +# originate from in an application. +transaction_tracer.stack_trace_threshold = 0.5 + +# Determines whether the agent will capture query plans for slow +# SQL queries. Only supported in MySQL and PostgreSQL. Set this +# to "false" to turn it off. +transaction_tracer.explain_enabled = true + +# Threshold for query execution time below which query plans +# will not not be captured. Relevant only when "explain_enabled" +# is true. +transaction_tracer.explain_threshold = 0.5 + +# Space separated list of function or method names in form +# 'module:function' or 'module:class.function' for which +# additional function timing instrumentation will be added. +transaction_tracer.function_trace = + +# The error collector captures information about uncaught +# exceptions or logged exceptions and sends them to UI for +# viewing. The error collector is enabled by default. Set this +# to "false" to turn it off. +error_collector.enabled = true + +# To stop specific errors from reporting to the UI, set this to +# a space separated list of the Python exception type names to +# ignore. The exception name should be of the form 'module:class'. +error_collector.ignore_errors = + +# Browser monitoring is the Real User Monitoring feature of the UI. +# For those Python web frameworks that are supported, this +# setting enables the auto-insertion of the browser monitoring +# JavaScript fragments. +browser_monitoring.auto_instrument = true + +# A thread profiling session can be scheduled via the UI when +# this option is enabled. The thread profiler will periodically +# capture a snapshot of the call stack for each active thread in +# the application to construct a statistically representative +# call tree. +thread_profiler.enabled = true + +# --------------------------------------------------------------------------- + +# +# The application environments. These are specific settings which +# override the common environment settings. The settings related to a +# specific environment will be used when the environment argument to the +# newrelic.agent.initialize() function has been defined to be either +# "development", "test", "staging" or "production". +# + +[newrelic:development] +monitor_mode = false + +[newrelic:test] +monitor_mode = false + +[newrelic:staging] +monitor_mode = true + +[newrelic:production] +monitor_mode = true + +# --------------------------------------------------------------------------- diff --git a/scripts/start-prod.sh b/scripts/start-prod.sh new file mode 100755 index 0000000..4969548 --- /dev/null +++ b/scripts/start-prod.sh @@ -0,0 +1,9 @@ +#! /bin/bash + + +# apply migrations onto db +poetry run alembic upgrade head + +# start server +NEW_RELIC_CONFIG_FILE=newrelic.ini newrelic-admin run-program gunicorn --worker-tmp-dir /dev/shm --workers=4 --bind 0.0.0.0:8000 --timeout 240 main:app +