Skip to content

Commit

Permalink
Merge pull request #190 from ZIFODS/183-deploy-with-terraform
Browse files Browse the repository at this point in the history
183 deploy with terraform
  • Loading branch information
Joseph Smith authored Nov 28, 2023
2 parents 5000a54 + ce1788f commit 08de8df
Show file tree
Hide file tree
Showing 9 changed files with 202 additions and 93 deletions.
90 changes: 68 additions & 22 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,40 +1,43 @@
on:
push:
branches: "*"
pull_request:
branches: [main, master]
name: Test, lint, build, push

on: workflow_dispatch

permissions:
id-token: write
contents: read

jobs:
test-dev:
timeout-minutes: 20
test:
name: "Test"
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
defaults:
run:
shell: bash

steps:
- name: Checkout
- name: Checkout repo
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::233044492909:role/skills-tracker-dvc
role-to-assume: arn:aws:iam::233044492909:role/SkillsTracker-GitHubActions
aws-region: eu-west-2
- name: Install DVC
uses: iterative/setup-dvc@v1
- name: Pull data with DVC
run: |
dvc pull --recursive
- name: Start containers
run: |
bash scripts/test-dev.sh

pre-commit:
- name: Configure DVC
run: bash scripts/configure_dvc.sh

- name: Test dev
run: bash scripts/test-dev.sh

lint:
name: "Lint"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v3
with:
python-version: "3.11"
python-version: "3.10"
- name: Install dev poetry env
run: |
python -m pip install --upgrade pip
Expand All @@ -43,3 +46,46 @@ jobs:
- name: Run pre-commit
run: |
poetry run pre-commit run --all-files
build:
name: "Build"
runs-on: ubuntu-latest
defaults:
run:
shell: bash

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::233044492909:role/SkillsTracker-GitHubActions
aws-region: eu-west-2

- name: Configure DVC
run: bash scripts/configure_dvc.sh

- name: Build containers
run: bash scripts/build-prod.sh

push:
name: "Push"
runs-on: ubuntu-latest
defaults:
run:
shell: bash

steps:
- name: Checkout repo
uses: actions/checkout@v3

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v2
with:
role-to-assume: arn:aws:iam::233044492909:role/SkillsTracker-GitHubActions
aws-region: eu-west-2

- name: Push to ECR
run: bash scripts/push-prod.sh
77 changes: 52 additions & 25 deletions app/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import os

from decouple import AutoConfig, Config, RepositoryEnv
from decouple import config

from app.utils.security.secrets import get_secret


class Env:
Expand All @@ -11,39 +13,64 @@ class Env:
PROD_ENV = False
if os.environ.get("SKILLS_ENV") == Env.PRODUCTION:
PROD_ENV = True
config = Config(RepositoryEnv(".env.prod"))
else:
config = AutoConfig()

# MongoDB Replica Set
# Front end endpoint
FRONTEND_URL = config("FRONTEND_URL", "http://localhost:3000")

# AWS
AWS_REGION = config("AWS_REGION", "eu-west-2")
AWS_SECRET_KMS_KEY = config("AWS_SECRET_KMS_KEY", "")
AWS_SECRET_NAME_NEO4J = config("AWS_SECRET_NAME_NEO4J", "")
AWS_SECRET_NAME_AZURE = config("AWS_SECRET_NAME_AZURE", "")
AWS_SECRET_NAME_API = config("AWS_SECRET_NAME_API", "")

# MongoDB
MONGODB_HOST = config("MONGODB_HOST", "localhost")
MONGODB_PORT = config("MONGODB_PORT", 27017, cast=int)
MONGODB_COLLECTION = "test"
MONGODB_DATABASE = "test"

# neo4j
NEO4J_URI = config("NEO4J_URI", "bolt://localhost:7687")
NEO4J_USER = config("NEO4J_USER", "neo4j")
NEO4J_PASSWORD = config("NEO4J_PASSWORD", "test")

# Azure login
AZURE_CLIENT_ID = config("AZURE_CLIENT_ID", None)
AZURE_CLIENT_SECRET = config("AZURE_CLIENT_SECRET", None)
AZURE_TENANT_ID = config("AZURE_TENANT_ID", "common")
AZURE_AUTHORITY = config(
"AZURE_AUTHORITY", f"https://login.microsoftonline.com/{AZURE_TENANT_ID}"
)
AZURE_DISCOVERY_URL = f"{AZURE_AUTHORITY}/v2.0/.well-known/openid-configuration"
AZURE_REDIRECT_URI = config("AZURE_REDIRECT_URI", None)

# Front end endpoint
FRONTEND_URL = config("FRONTEND_URL", "http://localhost:3000")

# Request session
SESSION_SECRET_KEY = config("SESSION_SECRET_KEY", None)
if PROD_ENV:
SESSION_SECRET = get_secret(AWS_SECRET_NAME_API, AWS_REGION, AWS_SECRET_KMS_KEY)
SESSION_SECRET_KEY = SESSION_SECRET["session_secret"]
else:
SESSION_SECRET_KEY = config("SESSION_SECRET_KEY", None)

# JWT access token configuration
JWT_SECRET_KEY = config("JWT_SECRET_KEY", None)
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 15
AUTH_TOKEN_EXPIRE_MINUTES = 1
if PROD_ENV:
JWT_SECRET_KEY = get_secret(AWS_SECRET_NAME_API, AWS_REGION, AWS_SECRET_KMS_KEY)
JWT_SECRET_KEY = SESSION_SECRET["jwt_secret"]
else:
JWT_SECRET_KEY = config("JWT_SECRET_KEY", None)

# neo4j
if PROD_ENV:
NEO4J_SECRET = get_secret(AWS_SECRET_NAME_NEO4J, AWS_REGION, AWS_SECRET_KMS_KEY)
NEO4J_URI = NEO4J_SECRET["uri"]
NEO4J_USERNAME = NEO4J_SECRET["username"]
NEO4J_PASSWORD = NEO4J_SECRET["password"]
else:
NEO4J_URI = config("NEO4J_URI", "bolt://localhost:7687")
NEO4J_USER = config("NEO4J_USER", "neo4j")
NEO4J_PASSWORD = config("NEO4J_PASSWORD", "test")

# Azure AD
if PROD_ENV:
AZURE_SECRET = get_secret(AWS_SECRET_NAME_AZURE, AWS_REGION, AWS_SECRET_KMS_KEY)
AZURE_CLIENT_ID = AZURE_SECRET["client_id"]
AZURE_TENANT_ID = AZURE_SECRET["tenant_id"]
AZURE_CLIENT_SECRET = AZURE_SECRET["client_secret"]
AZURE_REDIRECT_URI = AZURE_SECRET["redirect_uri"]
else:
AZURE_CLIENT_ID = config("AZURE_CLIENT_ID", None)
AZURE_CLIENT_SECRET = config("AZURE_CLIENT_SECRET", None)
AZURE_TENANT_ID = config("AZURE_TENANT_ID", "common")
AZURE_REDIRECT_URI = config("AZURE_REDIRECT_URI", None)
AZURE_AUTHORITY = config(
"AZURE_AUTHORITY", f"https://login.microsoftonline.com/{AZURE_TENANT_ID}"
)
AZURE_DISCOVERY_URL = f"{AZURE_AUTHORITY}/v2.0/.well-known/openid-configuration"
13 changes: 13 additions & 0 deletions app/utils/security/secrets.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import json

import boto3


def get_secret(secret_name: str, aws_region: str, aws_kms_key: str):
# Create a Secrets Manager client
session = boto3.session.Session()
client = session.client(service_name="secretsmanager", region_name=aws_region)

get_secret_value_response = client.get_secret_value(SecretId=secret_name)

return json.loads(get_secret_value_response[aws_kms_key])
31 changes: 9 additions & 22 deletions docker/api/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,37 +1,24 @@
FROM python:3.10 as base
FROM python:3.10-slim as base
LABEL maintainer="Joseph Smith"
LABEL version="0.1.0"
LABEL description="FastAPI server for Zifo Skills Tracker"

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

# Install wget for health check
RUN apt-get -y update && apt-get -y install wget

# Configure Poetry
ENV POETRY_VERSION=1.2.2
ENV POETRY_HOME=/opt/poetry
ENV POETRY_VENV=/opt/poetry-venv
ENV POETRY_CACHE_DIR=/opt/.cache

# Create and switch to a new user
RUN useradd --create-home skills-user
WORKDIR /home/skills-user
WORKDIR /app

# Install poetry separated from system interpreter
RUN python3 -m venv $POETRY_VENV \
&& $POETRY_VENV/bin/pip install -U pip setuptools \
&& $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
RUN pip install poetry

# Add `poetry` to PATH
ENV PATH="${PATH}:${POETRY_VENV}/bin"
COPY pyproject.toml .

# Install dependencies
COPY ./pyproject.toml ./pyproject.toml
RUN poetry install --without dev
RUN poetry install

# Copy source code
COPY ./app ./app

# Run the server
EXPOSE 8080
RUN mkdir ./data

CMD ["poetry", "run", "hypercorn", "app.main:app", "--reload", "--bind", "0.0.0.0:8080"]
31 changes: 7 additions & 24 deletions docker/api/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,31 +1,17 @@
FROM python:3.10 as base
LABEL maintainer="Joseph Smith"
LABEL version="0.1.0"
LABEL description="FastAPI server for Zifo Skills Tracker"
FROM python:3.10-slim as base

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

# Install wget for health check
RUN apt-get -y update && apt-get -y install wget

# Configure Poetry
ENV POETRY_VERSION=1.2.2
ENV POETRY_HOME=/opt/poetry
ENV POETRY_VENV=/opt/poetry-venv
ENV POETRY_CACHE_DIR=/opt/.cache

# Create and switch to a new user
RUN useradd --create-home skills-user
WORKDIR /home/skills-user
WORKDIR /app

# Install poetry separated from system interpreter
RUN python3 -m venv $POETRY_VENV \
&& $POETRY_VENV/bin/pip install -U pip setuptools \
&& $POETRY_VENV/bin/pip install poetry==${POETRY_VERSION}
RUN pip install poetry

# Add `poetry` to PATH
ENV PATH="${PATH}:${POETRY_VENV}/bin"
COPY pyproject.toml .

# Install dependencies
COPY ./pyproject.toml ./pyproject.toml
RUN poetry install

# Copy source code
Expand All @@ -34,7 +20,4 @@ COPY ./pipeline ./pipeline
COPY ./tests ./tests
RUN mkdir ./data

# Run the server
EXPOSE 8080

CMD ["poetry", "run", "hypercorn", "app.main:app", "--reload", "--bind", "0.0.0.0:8080"]
4 changes: 4 additions & 0 deletions docker/docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ services:
extends:
file: ./docker-compose.prod.yml
service: react-frontend
image: zifo-skills-frontend
build:
context: ..
dockerfile: ./docker/frontend/Dockerfile
environment:
- REACT_APP_API_URL=http://localhost:8080/
depends_on:
Expand Down
16 changes: 16 additions & 0 deletions scripts/build-prod.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/bash

AWS_ACCOUNT_ID="233044492909"
AWS_REGION="eu-west-2"

# Frontend
ECR_REPO_NAME_FRONTEND="skills-tracker-frontend"
ECR_REPO_URI_FRONTEND="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_FRONTEND"

docker build -t "$ECR_REPO_URI_FRONTEND:latest" -f docker/frontend/Dockerfile .

# API
ECR_REPO_NAME_API="skills-tracker-api"
ECR_REPO_URI_API="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_API"

docker build -t "$ECR_REPO_URI_API:latest" -f docker/api/Dockerfile .
13 changes: 13 additions & 0 deletions scripts/configure_dvc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Install DVC
sudo wget \
https://dvc.org/deb/dvc.list \
-O /etc/apt/sources.list.d/dvc.list
wget -qO - https://dvc.org/deb/iterative.asc | gpg --dearmor > packages.iterative.gpg
sudo install -o root -g root -m 644 packages.iterative.gpg /etc/apt/trusted.gpg.d/
rm -f packages.iterative.gpg
sudo apt update
sudo apt install dvc

# Configure DVC
dvc remote modify --local s3 credentialpath '~/.aws/credentials'
dvc pull --recursive
20 changes: 20 additions & 0 deletions scripts/push-prod.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#!/bin/bash

AWS_ACCOUNT_ID="233044492909"
AWS_REGION="eu-west-2"

# Frontend
ECR_REPO_NAME_FRONTEND="skills-tracker-frontend"
ECR_REPO_URI_FRONTEND="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_FRONTEND"

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_FRONTEND

docker push "$ECR_REPO_URI_FRONTEND:latest"

# API
ECR_REPO_NAME_API="skills-tracker-api"
ECR_REPO_URI_API="$AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_API"

aws ecr get-login-password --region $AWS_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_REGION.amazonaws.com/$ECR_REPO_NAME_API

docker push "$ECR_REPO_URI_API:latest"

0 comments on commit 08de8df

Please sign in to comment.