Merge pull request #107 from HideyoshiSolutions/better-deployment

Better deployment Using Kubeconfig and Better EnvSubts
This commit is contained in:
2024-10-20 22:31:19 -03:00
committed by GitHub
28 changed files with 447 additions and 642 deletions

49
.env.example Normal file
View File

@@ -0,0 +1,49 @@
KUBE_NAMESPACE=
MASTER_NODE_LABEL=
WORKER_NODE_LABEL=
# Certificates Secrets
KUBE_CERT_SERVER=
KUBE_DOMAIN_ORGANIZATION=
KUBE_DOMAIN_EMAIL=
KUBE_DOMAIN=
KUBE_API_DOMAIN=
# Backend Secrets
KUBE_BACKEND_TOKEN_SECRET=
KUBE_BACKEND_ACCESS_TOKEN_DURATION=
KUBE_BACKEND_REFRESH_TOKEN_DURATION=
KUBE_BACKEND_DEFAULT_USER_FULL_NAME=
KUBE_BACKEND_DEFAULT_USER_EMAIL=
KUBE_BACKEND_DEFAULT_USER_USERNAME=
KUBE_BACKEND_DEFAULT_USER_PASSWORD=
KUBE_BACKEND_GOOGLE_CLIENT_ID=
KUBE_BACKEND_GOOGLE_CLIENT_SECRET=
KUBE_BACKEND_GOOGLE_REDIRECT_URL=
KUBE_BACKEND_GITHUB_CLIENT_ID=
KUBE_BACKEND_GITHUB_CLIENT_SECRET=
KUBE_BACKEND_GITHUB_REDIRECT_URL=
# Frontend Secrets
KUBE_FRONTEND_URL=
KUBE_FRONTEND_BACKEND_URL=
KUBE_FRONTEND_OAUTH_URL=
KUBE_FRONTEND_GITHUB_USER=
# Database Secrets (Postgres)
KUBE_DATABASE_NAME=
KUBE_DATABASE_USER=
KUBE_DATABASE_PASSWORD=
# Redis Secrets
KUBE_REDIS_PASSWORD=
# Storage Secrets (AWS S3)
KUBE_STORAGE_TYPE=
KUBE_STORAGE_AWS_ACCESS_KEY_ID=
KUBE_STORAGE_AWS_SECRET_ACCESS_KEY=
KUBE_STORAGE_AWS_REGION=
KUBE_STORAGE_AWS_BUCKET=
KUBE_STORAGE_VIRUS_CHECKER_TYPE=
KUBE_STORAGE_VIRUS_CHECKER_API_KEY=

30
.github/workflows/deploy-cluster.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: remote ssh command
on:
repository_dispatch:
types: [deploy-prod]
push:
branches:
- main
- staging
jobs:
deploy:
name: Deploy to Cluster
environment: ${{ github.ref_name == 'main' && 'prod' || 'staging' }}
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Writing Env File
run: |
echo "${{ secrets.ENV_FILE }}" | base64 -d > .env
- name: Set Kubernetes Context
uses: azure/k8s-set-context@v1
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Execute deploy
run: |
./deploy.sh -f .env

View File

@@ -1,58 +0,0 @@
name: remote ssh command
on:
repository_dispatch:
types: [deploy-prod]
push:
branches:
- main
jobs:
build:
name: Build
environment: prod
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Create Config Json File
run: |
echo "${{ secrets.CONFIG_JSON }}" | base64 -d > config.json
- name: Inserts Prod Enviromental Variables
run: |
python -m pip install --upgrade pip pipenv
pipenv install
pipenv run python setup.py -e prod -f config.json
- name: copy file via ssh
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
source: "."
target: "infra-hideyoshi.com"
- name: executing remote ssh commands
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
command_timeout: 30m
script: |
sudo apt update && sudo apt install -y jq
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
source ~/.profile
cd infra-hideyoshi.com
./deploy.sh --prod
./refresh.sh

View File

@@ -1,56 +0,0 @@
name: remote ssh command
on:
push:
branches:
- staging
jobs:
build:
name: Build
environment: staging
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up Python 3.8
uses: actions/setup-python@v3
with:
python-version: "3.10"
- name: Create Config Json File
run: |
echo "${{ secrets.CONFIG_JSON }}" | base64 -d > config.json
- name: Inserts Prod Enviromental Variables
run: |
python -m pip install --upgrade pip pipenv
pipenv install
pipenv run python setup.py -e staging -f config.json
- name: copy file via ssh
uses: appleboy/scp-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
source: "."
target: "infra-hideyoshi.com"
- name: executing remote ssh commands
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
command_timeout: 30m
script: |
sudo apt update && sudo apt install -y jq
curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3 | bash
source ~/.profile
cd infra-hideyoshi.com
./deploy.sh --staging
./refresh.sh

View File

@@ -5,40 +5,32 @@ on:
types: [refresh-deployments]
jobs:
refresh-deployments:
name: Refresh deployments
refresh_deployment:
name: Refresh Kubernetes Deployments
environment: prod
runs-on: ubuntu-latest
timeout-minutes: 30
env:
deployments: ${{ github.event.client_payload.deployments }}
steps:
- name: Checkout
uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Writing Env File
run: |
echo "${{ secrets.ENV_FILE }}" | base64 -d > .env
- name: Executing Remote Commands - Refresh All Deployments
env:
deployments: ${{ github.event.client_payload.deployments }}
- name: Set Kubernetes Context
uses: azure/k8s-set-context@v1
with:
method: kubeconfig
kubeconfig: ${{ secrets.KUBE_CONFIG }}
- name: Refresh Deployments
if: ${{ env.deployments == '' }}
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
script: |
[[ -d infra-hideyoshi.com ]] && \
cd infra-hideyoshi.com && \
./refresh.sh
run: |
./deploy.sh -f .env -r
- name: Executing Remote Commands - Refresh Specific Deployments
env:
deployments: ${{ github.event.client_payload.deployments }}
- name: Refresh Specific Deployments
if: ${{ env.deployments != '' }}
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
port: ${{ secrets.SSH_PORT }}
key: ${{ secrets.SSH_KEY }}
script: |
[[ -d infra-hideyoshi.com ]] && \
cd infra-hideyoshi.com && \
./refresh.sh ${{ env.deployments }}
run: |
./deploy.sh -f .env -r ${{ env.deployments }}

3
.gitignore vendored
View File

@@ -2,12 +2,15 @@
.vscode/
.env*
!.env.example
.secret*
**/*.json
!**/*.example.json
*.patch
*KUBECONFIG*
**/cert-manager-certificate.yaml
**/nginx-ingress-api.yaml
**/nginx-ingress-root.yaml

13
Pipfile
View File

@@ -1,13 +0,0 @@
[[source]]
url = "https://pypi.org/simple"
verify_ssl = true
name = "pypi"
[packages]
python-dotenv = "*"
envsubst = "*"
[dev-packages]
[requires]
python_version = "3"

37
Pipfile.lock generated
View File

@@ -1,37 +0,0 @@
{
"_meta": {
"hash": {
"sha256": "9127f5121153ee714035c045f3621c810565d451e8dd461576f24e165e55f73d"
},
"pipfile-spec": 6,
"requires": {
"python_version": "3"
},
"sources": [
{
"name": "pypi",
"url": "https://pypi.org/simple",
"verify_ssl": true
}
]
},
"default": {
"envsubst": {
"hashes": [
"sha256:7188f9f2a046e45b63098ce5a7fd84126cbe9e5b73b8ff78eaf6e32122c0caaf",
"sha256:d8e402984a84dda4ea7a8a1f7afe1c41e54a1257cfb74c80cb8f991053d97b9b"
],
"index": "pypi",
"version": "==0.1.5"
},
"python-dotenv": {
"hashes": [
"sha256:a8df96034aae6d2d50a4ebe8216326c61c3eb64836776504fcca410e5937a3ba",
"sha256:f5971a9226b701070a4bf2c38c89e5a3f0d64de8debda981d1db98583009122a"
],
"index": "pypi",
"version": "==1.0.0"
}
},
"develop": {}
}

273
deploy.sh
View File

@@ -1,21 +1,82 @@
#!/bin/bash
#!/bin/sh
function check_for_dependencies() {
if ! command -v kubectl &>/dev/null; then
validate_dependencies() {
if ! command -v kubectl &> /dev/null; then
echo "kubectl could not be found"
exit 1
fi
if ! command -v jq &>/dev/null; then
echo "jq could not be found"
exit 1
fi
if ! command -v helm &>/dev/null; then
if ! command -v helm &> /dev/null; then
echo "helm could not be found"
exit 1
fi
if ! command -v envsubst &> /dev/null; then
echo "envsubst could not be found"
exit 1
fi
if [[ $environment == "local" ]]; then
if ! command -v minikube &> /dev/null; then
echo "minikube could not be found"
exit 1
fi
fi
echo "Dependencies validated"
}
function configure_nginx_ingress() {
read_env_file() {
if [ -f $1 ]; then
set -a && source $1 && set +a;
fi
}
build_secret_envs() {
for i in $(env | grep -E '^KUBE_[a-zA-Z_][a-zA-Z0-9_]*=' | cut -d= -f1); do
eval "export ${i}_B64=$(echo -n ${!i} | base64 -w0)"
done
}
apply_template() {
echo -e "\n\n----------------------------------------------------\n"
echo -e "Applying: $1\n"
echo -e "----------------------------------------------------\n\n\n"
envsubst < $1 | kubectl apply -f -
}
apply_deployment() {
deployment_name=$1
deployment_files=$2
for file in $(find $2 -type f); do
apply_template $file
done
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/${deployment_name} \
-n ${KUBE_NAMESPACE}
}
configure_nginx_minikube() {
if [[ $setup_minikube == "true" ]]; then
minikube start --driver kvm2 --cpus 2 --memory 4Gib
fi
minikube addons enable ingress-dns
minikube addons enable ingress
}
configure_nginx_ingress() {
helm upgrade --install ingress-nginx ingress-nginx \
--repo https://kubernetes.github.io/ingress-nginx \
--namespace ingress-nginx --create-namespace
@@ -26,7 +87,8 @@ function configure_nginx_ingress() {
--timeout=120s
}
function configure_cert_manager() {
configure_cert_manager() {
helm repo add jetstack https://charts.jetstack.io --force-update
helm repo update
helm install cert-manager jetstack/cert-manager \
@@ -34,121 +96,148 @@ function configure_cert_manager() {
--create-namespace \
--version v1.14.2 \
--set installCRDs=true \
--timeout=600s
--timeout=600s || echo "Cert Manager already installed"
}
function configure_postgres() {
configure_postgres() {
helm repo add cnpg https://cloudnative-pg.github.io/charts
helm upgrade --install cnpg \
--namespace portfolio \
--namespace ${KUBE_NAMESPACE} \
--create-namespace \
cnpg/cloudnative-pg
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/cnpg-cloudnative-pg \
-n portfolio
-n ${KUBE_NAMESPACE}
kubectl apply -f ./deployment/postgres/cn-cluster.yaml
apply_template "./template/postgres/cn-cluster.template.yaml"
kubectl wait --for=condition=Ready \
--timeout=600s \
cluster/postgres-cn-cluster \
-n portfolio
-n ${KUBE_NAMESPACE}
}
function application_deploy() {
kubectl create secret generic backend-secret -n portfolio \
--from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/backendSecret.json)
kubectl create secret generic frontend-secret -n portfolio \
--from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/frontendSecret.json)
kubectl create secret generic redis-secret -n portfolio \
--from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/redisSecret.json)
kubectl create secret generic storage-secret -n portfolio \
--from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/storageSecret.json)
kubectl apply -f ./deployment/redis
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/redis-deployment \
-n portfolio
kubectl apply -f ./deployment/frontend
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/frontend-deployment \
-n portfolio
kubectl apply -f ./deployment/storage
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/storage-deployment \
-n portfolio
kubectl apply -f ./deployment/backend
kubectl wait --for=condition=available \
--timeout=600s \
deployment.apps/backend-deployment \
-n portfolio
kubectl apply -f \
./deployment/nginx-ingress
}
function main() {
check_for_dependencies
if [[ $1 == "--local" || $1 == "-l" ]]; then
function kubectl {
minikube kubectl -- $@
}
minikube start --driver kvm2 --cpus 2 --memory 4Gib
minikube addons enable ingress-dns
minikube addons enable ingress
configure_ingress() {
apply_template "./template/nginx-ingress/nginx-ingress-root.template.yaml"
if [[ $environment == "local" ]]; then
apply_template "./template/cert-manager/cert-manager-issuer-dev.yaml"
else
apply_template "./template/cert-manager/cert-manager-issuer.yaml"
fi
apply_template "./template/cert-manager/cert-manager-certificate.template.yaml"
}
deploy_kubernetes() {
if [[ $environment == "local" ]]; then
configure_nginx_minikube
else
configure_nginx_ingress
fi
configure_cert_manager
kubectl apply -f ./deployment/portfolio-namespace.yaml
KUBE_FILES=(
"./template/portfolio-namespace.template.yaml"
"./template/portfolio-secret.template.yml"
)
for file in ${KUBE_FILES[@]}; do
apply_template $file
done
configure_postgres
application_deploy
apply_deployment "redis-deployment" "./template/redis"
if [[ $1 == "--local" || $1 == "-l" ]]; then
apply_deployment "storage-deployment" "./template/storage"
kubectl apply -f \
./deployment/cert-manager/cert-manager-issuer-dev.yaml
apply_deployment "backend-deployment" "./template/backend"
kubectl apply -f \
./deployment/cert-manager/cert-manager-certificate.yaml
apply_deployment "frontend-deployment" "./template/frontend"
echo "http://$(/usr/bin/minikube ip)"
else
kubectl apply -f \
./deployment/cert-manager/cert-manager-issuer.yaml
kubectl apply -f \
./deployment/cert-manager/cert-manager-certificate.yaml
configure_ingress
if [[ $environment == "local" ]]; then
echo "Minikube IP: http://$(minikube ip)"
fi
exit 0
}
main $1
main() {
build_secret_envs
deploy_kubernetes $@
}
refresh() {
deployments=$1
if [[ -z $1 ]]; then
deployments=(
"redis-deployment"
"storage-deployment"
"backend-deployment"
"frontend-deployment"
)
fi
for deployment in ${deployments[@]}; do
kubectl rollout restart deployment/${deployment} -n ${KUBE_NAMESPACE}
done
}
environment="remote"
setup_minikube="false"
execution_mode="deploy"
while getopts ":f:e:mrh" opt; do
case ${opt} in
f )
echo "Reading env file: ${OPTARG}"
read_env_file ${OPTARG}
;;
e )
[[ ${OPTARG} == "local" ]] && environment="local"
echo "Environment: ${OPTARG}"
;;
m )
setup_minikube="true"
echo "Setting up minikube"
;;
h )
echo "Usage: deploy.sh [-f <env_file>] [-e <environment>] [-m <minikube>]"
exit 0
;;
r )
echo "Executing Refresh"
execution_mode="refresh"
eval nextopt=\${$OPTIND}
if [[ -n $nextopt && $nextopt != -* ]]; then
OPTIND=$((OPTIND + 1))
refresh_deployments=($nextopt)
fi
;;
*)
echo "Invalid option: $OPTARG"
exit 1
;;
esac
done
validate_dependencies
if [[ $execution_mode == "deploy" ]]; then
main
elif [[ $execution_mode == "refresh" ]]; then
[[ -z $refresh_deployments ]] && refresh || refresh $refresh_deployments
else
echo "Invalid execution mode: $execution_mode"
exit 1
fi

View File

@@ -1,39 +0,0 @@
{
"backendSecret": {
"tokenSecret": "",
"accessTokenDuration": "",
"refreshTokenDuration": "",
"defaultUserFullName": "",
"defaultUserEmail": "",
"defaultUserUsername": "",
"defaultUserPassword": "",
"googleClientId": "",
"googleClientSecret": "",
"googleRedirectUrl": "",
"githubClientId": "",
"githubClientSecret": "",
"githubRedirectUrl": ""
},
"frontendSecret": {
"frontendPath": "",
"backendUrl": "",
"backendOAuthUrl": ""
},
"postgresSecret": {
"postgresDatabase": "",
"postgresUser": "",
"postgresPassword": ""
},
"redisSecret": {
"redisPassword": ""
},
"storageSecret": {
"storageType": "",
"awsAccessKeyId": "",
"awsSecretAccessKey": "",
"awsRegion": "",
"awsBucket": "",
"virusCheckerType": "",
"virusCheckerApiKey": ""
}
}

View File

@@ -1,47 +0,0 @@
#!/bin/bash
function refresh_kubernetes_secrets() {
kubectl delete secret backend-secret -n portfolio
kubectl delete secret frontend-secret -n portfolio
kubectl delete secret postgres-secret -n portfolio
kubectl delete secret redis-secret -n portfolio
kubectl delete secret storage-secret -n portfolio
kubectl create secret generic backend-secret -n portfolio --from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/backendSecret.json)
kubectl create secret generic frontend-secret -n portfolio --from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/frontendSecret.json)
kubectl create secret generic postgres-secret -n portfolio --from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/postgresSecret.json)
kubectl create secret generic redis-secret -n portfolio --from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/redisSecret.json)
kubectl create secret generic storage-secret -n portfolio --from-env-file <(jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" ./deployment/secrets/storageSecret.json)
}
function refresh_kubernetes_deployments() {
NAMESPACES=(
portfolio
)
DEPLOYMENTS=("$@")
for i in "${NAMESPACES[@]}"; do
for x in "${DEPLOYMENTS[@]}"; do
PODS=$(kubectl -n $i get pods --no-headers | awk '{print $1}' | grep $x | tr '\n' ' ')
kubectl -n $i delete pods $PODS
done
done
}
if [ $# -eq 0 ]; then
DEPLOYMENTS=(
"frontend-deployment"
"backend-deployment"
"storage-deployment"
"storage-processor-deployment"
)
else
DEPLOYMENTS=("$@")
fi
refresh_kubernetes_secrets
refresh_kubernetes_deployments "${NAMESPACES[@]}" "${DEPLOYMENTS[@]}"

208
setup.py
View File

@@ -1,208 +0,0 @@
from base64 import b64decode, b64encode
from dotenv import load_dotenv
from envsubst import envsubst
from pathlib import Path, PosixPath
import argparse
import warnings
import json
import os
def write_template(template: str, output: str):
os.makedirs(os.path.dirname(output), exist_ok=True)
with open(template, 'r') as template,\
open(output, 'w') as output:
output.write(envsubst(template.read()))
def configure_env_variables(environment: str):
if not environment in ("prod", "staging", "local"):
raise ValueError("Invalid Environment Selected")
match environment:
case "local":
DOMAIN = "local.hideyoshi.com.br"
API_DOMAIN = "api.local.hideyoshi.com.br"
MASTER_NODE_LABEL = "minikube.k8s.io/name: minikube"
WORKER_NODE_LABEL = "minikube.k8s.io/name: minikube"
case "staging":
DOMAIN = "staging.hideyoshi.com.br"
API_DOMAIN = "api.staging.hideyoshi.com.br"
MASTER_NODE_LABEL = "node_type: master"
WORKER_NODE_LABEL = "node_type: worker"
case _:
DOMAIN = "hideyoshi.com.br"
API_DOMAIN = "api.hideyoshi.com.br"
MASTER_NODE_LABEL = "node_type: master"
WORKER_NODE_LABEL = "node_type: worker"
os.environ["DOMAIN"] = DOMAIN
os.environ["API_DOMAIN"] = API_DOMAIN
os.environ["MASTER_NODE_LABEL"] = MASTER_NODE_LABEL
os.environ["WORKER_NODE_LABEL"] = WORKER_NODE_LABEL
def configure_templates(environment: str):
MAPPINS = [
{"template": "template/cert-manager/cert-manager-certificate.template.yaml", "output": "deployment/cert-manager/cert-manager-certificate.yaml"},
{"template": "template/nginx-ingress/nginx-ingress-root.template.yaml", "output": "deployment/nginx-ingress/nginx-ingress-root.yaml"},
{"template": "template/postgres/cn-cluster.template.yaml", "output": "deployment/postgres/cn-cluster.yaml"},
{"template": "template/frontend/frontend.template.yaml", "output": "deployment/frontend/frontend.yaml"},
{"template": "template/backend/backend.template.yaml", "output": "deployment/backend/backend.yaml"},
{"template": "template/storage/storage-processor.template.yaml", "output": "deployment/storage/storage-processor.yaml"},
{"template": "template/storage/storage.template.yaml", "output": "deployment/storage/storage.yaml"},
]
for mapping in MAPPINS:
write_template(mapping["template"], mapping["output"])
def validate_backend_secret(secret: str):
required_keys = [
'tokenSecret',
'accessTokenDuration',
'refreshTokenDuration',
'defaultUserFullName',
'defaultUserEmail',
'defaultUserUsername',
'defaultUserPassword',
'googleClientId',
'googleClientSecret',
'googleRedirectUrl',
'githubClientId',
'githubClientSecret',
'githubRedirectUrl'
]
for key in required_keys:
if key not in secret:
raise ValueError(f"Key {key} not found in backendSecret")
def validate_frontend_secret(secret: str):
required_keys = [
'frontendPath',
'backendUrl',
'backendOAuthUrl',
'githubUser'
]
for key in required_keys:
if key not in secret:
raise ValueError(f"Key {key} not found in frontendSecret")
def validate_postgres_secret(secret: str):
required_keys = [
'postgresUser',
'postgresPassword',
'postgresDatabase'
]
for key in required_keys:
if key not in secret:
raise ValueError(f"Key {key} not found in postgresSecret")
def validate_redis_secret(secret: str):
required_keys = [
'redisPassword',
]
for key in required_keys:
if key not in secret:
raise ValueError(f"Key {key} not found in redisSecret")
def validate_storage_secret(secret: str):
required_keys = [
'storageType',
'awsAccessKeyId',
'awsSecretAccessKey',
'awsRegion',
'awsBucket',
'virusCheckerType',
'virusCheckerApiKey',
]
for key in required_keys:
if key not in secret:
raise ValueError(f"Key {key} not found in storageSecret")
def validate_env(env: dict):
required_secrets = [
'backendSecret',
'frontendSecret',
'postgresSecret',
'redisSecret',
'storageSecret',
]
for secret in required_secrets:
if secret not in env:
raise ValueError(f"Secret {secret} not found in env.json")
if secret == 'backendSecret':
validate_backend_secret(env[secret])
if secret == 'frontendSecret':
validate_frontend_secret(env[secret])
if secret == 'postgresSecret':
validate_postgres_secret(env[secret])
if secret == 'redisSecret':
validate_redis_secret(env[secret])
if secret == 'storageSecret':
validate_storage_secret(env[secret])
def write_secrets_to_file(env: dict):
for key, secret in env.items():
secrets_dir = Path("deployment", "secrets")
if not secrets_dir.exists():
secrets_dir.mkdir()
with open(secrets_dir.joinpath(f"{key}.json"), "w") as f:
json.dump(secret, f, indent=4)
def read_env_json(file: str) -> dict:
with open(file, "r") as f:
return json.load(f)
def main(file, environment):
env = read_env_json(file)
validate_env(env)
write_secrets_to_file(env)
configure_env_variables(environment)
configure_templates(environment)
if __name__ == "__main__":
parser = argparse.ArgumentParser(prog="Setup")
parser.add_argument(
"-f", "--file",
dest="file",
default=".env",
help="Secret file [default = .secret]"
)
parser.add_argument(
"-e", "--environment",
dest="environment",
default="prod",
help="Selected Deployment Environment [default = prod, options = [prod, staging, dev]]"
)
args = parser.parse_args()
main(**vars(args))

View File

@@ -1,9 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: backend-config
data:
backend_url: backend-service
backend_port: "8070"
backend_db_name: portfolio
backend_db_name: ${KUBE_DATABASE_NAME}

View File

@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: backend-deployment
spec:
replicas: 1
@@ -15,6 +15,18 @@ spec:
spec:
nodeSelector:
${WORKER_NODE_LABEL}
initContainers:
- name: wait-storage-init
image: busybox:latest
args:
- /bin/sh
- -c
- >
set -x;
while [ $(curl -sw '%{http_code}' "storage-service:8070/health" -o /dev/null) -ne 200 ]; do
sleep 15;
done
containers:
- name: backend
image: yoshiunfriendly/backend-hideyoshi.com
@@ -32,7 +44,7 @@ spec:
httpGet:
path: /health
port: 8070
initialDelaySeconds: 240
initialDelaySeconds: 60
livenessProbe:
httpGet:
path: /health
@@ -43,49 +55,49 @@ spec:
valueFrom:
secretKeyRef:
name: frontend-secret
key: frontendPath
key: frontendUrl
- name: TOKEN_SECRET
valueFrom:
secretKeyRef:
name: backend-secret
key: tokenSecret
key: backendTokenSecret
- name: ACCESS_TOKEN_DURATION
valueFrom:
secretKeyRef:
name: backend-secret
key: accessTokenDuration
key: backendAccessTokenDuration
- name: REFRESH_TOKEN_DURATION
valueFrom:
secretKeyRef:
name: backend-secret
key: refreshTokenDuration
key: backendRefreshTokenDuration
- name: DEFAULT_USER_FULLNAME
valueFrom:
secretKeyRef:
name: backend-secret
key: defaultUserFullName
key: backendDefaultUserFullName
- name: DEFAULT_USER_EMAIL
valueFrom:
secretKeyRef:
name: backend-secret
key: defaultUserEmail
key: backendDefaultUserEmail
- name: DEFAULT_USER_USERNAME
valueFrom:
secretKeyRef:
name: backend-secret
key: defaultUserUsername
key: backendDefaultUserUsername
- name: DEFAULT_USER_PASSWORD
valueFrom:
secretKeyRef:
name: backend-secret
key: defaultUserPassword
key: backendDefaultUserPassword
- name: PORT
valueFrom:
@@ -97,37 +109,37 @@ spec:
valueFrom:
secretKeyRef:
name: backend-secret
key: googleClientId
key: backendGoogleClientId
- name: GOOGLE_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: backend-secret
key: googleClientSecret
key: backendGoogleClientSecret
- name: GOOGLE_REDIRECT_URL
valueFrom:
secretKeyRef:
name: backend-secret
key: googleRedirectUrl
key: backendGoogleRedirectUrl
- name: GITHUB_CLIENT_ID
valueFrom:
secretKeyRef:
name: backend-secret
key: githubClientId
key: backendGithubClientId
- name: GITHUB_CLIENT_SECRET
valueFrom:
secretKeyRef:
name: backend-secret
key: githubClientSecret
key: backendGithubClientSecret
- name: GITHUB_REDIRECT_URL
valueFrom:
secretKeyRef:
name: backend-secret
key: githubRedirectUrl
key: backendGithubRedirectUrl
- name: POSTGRES_URL
valueFrom:
@@ -193,7 +205,7 @@ spec:
apiVersion: v1
kind: Service
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: backend-service
spec:
selector:

View File

@@ -2,15 +2,15 @@ apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: letsencrypt-cluster-certificate
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
spec:
dnsNames:
- ${DOMAIN}
- ${API_DOMAIN}
- ${KUBE_DOMAIN}
- ${KUBE_API_DOMAIN}
secretName: letsencrypt-cluster-certificate-tls
issuerRef:
name: cluster-certificate-issuer
kind: ClusterIssuer
subject:
organizations:
- Hideyoshi
- ${KUBE_DOMAIN_ORGANIZATION}

View File

@@ -4,8 +4,8 @@ metadata:
name: cluster-certificate-issuer
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: vitor.h.n.batista@gmail.com
server: ${KUBE_CERT_SERVER}
email: ${KUBE_DOMAIN_EMAIL}
privateKeySecretRef:
name: cluster-certificate-issuer
solvers:

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: frontend-config
data:
frontend_url: frontend-service

View File

@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: frontend-deployment
labels:
app: frontend
@@ -17,6 +17,17 @@ spec:
spec:
nodeSelector:
${WORKER_NODE_LABEL}
initContainers:
- name: wait-backend-init
image: busybox:latest
args:
- /bin/sh
- -c
- >
set -x;
while [ $(curl -sw '%{http_code}' "backend-service:8000/health" -o /dev/null) -ne 200 ]; do
sleep 15;
done
containers:
- name: frontend
image: yoshiunfriendly/frontend-hideyoshi.com:latest
@@ -47,23 +58,23 @@ spec:
valueFrom:
secretKeyRef:
name: frontend-secret
key: backendUrl
key: frontendBackendUrl
- name: BACKEND_OAUTH_URL
valueFrom:
secretKeyRef:
name: frontend-secret
key: backendOAuthUrl
key: frontendOAuthUrl
- name: GITHUB_USER
valueFrom:
secretKeyRef:
name: frontend-secret
key: githubUser
key: frontendGithubUser
---
apiVersion: v1
kind: Service
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: frontend-service
spec:
selector:

View File

@@ -1,7 +1,7 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: nginx-ingress
annotations:
kubernetes.io/ingress.class: nginx
@@ -10,11 +10,11 @@ metadata:
spec:
tls:
- hosts:
- ${DOMAIN}
- ${API_DOMAIN}
- ${KUBE_DOMAIN}
- ${KUBE_API_DOMAIN}
secretName: letsencrypt-cluster-certificate-tls
rules:
- host: ${DOMAIN}
- host: ${KUBE_DOMAIN}
http:
paths:
- path: /
@@ -24,7 +24,7 @@ spec:
name: frontend-service
port:
number: 5000
- host: ${API_DOMAIN}
- host: ${KUBE_API_DOMAIN}
http:
paths:
- path: /

View File

@@ -1,4 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: portfolio
name: ${KUBE_NAMESPACE}

View File

@@ -0,0 +1,77 @@
apiVersion: v1
kind: Secret
metadata:
name: backend-secret
namespace: ${KUBE_NAMESPACE}
type: Opaque
data:
backendTokenSecret: ${KUBE_BACKEND_TOKEN_SECRET_B64}
backendAccessTokenDuration: ${KUBE_BACKEND_ACCESS_TOKEN_DURATION_B64}
backendRefreshTokenDuration: ${KUBE_BACKEND_REFRESH_TOKEN_DURATION_B64}
backendDefaultUserFullName: ${KUBE_BACKEND_DEFAULT_USER_FULL_NAME_B64}
backendDefaultUserEmail: ${KUBE_BACKEND_DEFAULT_USER_EMAIL_B64}
backendDefaultUserUsername: ${KUBE_BACKEND_DEFAULT_USER_USERNAME_B64}
backendDefaultUserPassword: ${KUBE_BACKEND_DEFAULT_USER_PASSWORD_B64}
backendGoogleClientId: ${KUBE_BACKEND_GOOGLE_CLIENT_ID_B64}
backendGoogleClientSecret: ${KUBE_BACKEND_GOOGLE_CLIENT_SECRET_B64}
backendGoogleRedirectUrl: ${KUBE_BACKEND_GOOGLE_REDIRECT_URL_B64}
backendGithubClientId: ${KUBE_BACKEND_GITHUB_CLIENT_ID_B64}
backendGithubClientSecret: ${KUBE_BACKEND_GITHUB_CLIENT_SECRET_B64}
backendGithubRedirectUrl: ${KUBE_BACKEND_GITHUB_REDIRECT_URL_B64}
---
apiVersion: v1
kind: Secret
metadata:
name: frontend-secret
namespace: ${KUBE_NAMESPACE}
type: Opaque
data:
frontendUrl: ${KUBE_FRONTEND_URL_B64}
frontendBackendUrl: ${KUBE_FRONTEND_BACKEND_URL_B64}
frontendOAuthUrl: ${KUBE_FRONTEND_OAUTH_URL_B64}
frontendGithubUser: ${KUBE_FRONTEND_GITHUB_USER_B64}
---
apiVersion: v1
kind: Secret
metadata:
name: database-secret
namespace: ${KUBE_NAMESPACE}
type: Opaque
data:
databaseName: ${KUBE_DATABASE_NAME_B64}
databaseUser: ${KUBE_DATABASE_USER_B64}
databasePassword: ${KUBE_DATABASE_PASSWORD_B64}
---
apiVersion: v1
kind: Secret
metadata:
name: redis-secret
namespace: ${KUBE_NAMESPACE}
type: Opaque
data:
redisPassword: ${KUBE_REDIS_PASSWORD_B64}
---
apiVersion: v1
kind: Secret
metadata:
name: storage-secret
namespace: ${KUBE_NAMESPACE}
type: Opaque
data:
storageType: ${KUBE_STORAGE_TYPE_B64}
storageAwsAccessKeyId: ${KUBE_STORAGE_AWS_ACCESS_KEY_ID_B64}
storageAwsSecretAccessKey: ${KUBE_STORAGE_AWS_SECRET_ACCESS_KEY_B64}
storageAwsRegion: ${KUBE_STORAGE_AWS_REGION_B64}
storageAwsBucket: ${KUBE_STORAGE_AWS_BUCKET_B64}
storageVirusCheckerType: ${KUBE_STORAGE_VIRUS_CHECKER_TYPE_B64}
storageVirusCheckerApiKey: ${KUBE_STORAGE_VIRUS_CHECKER_API_KEY_B64}

View File

@@ -2,7 +2,7 @@ apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: postgres-cn-cluster
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
spec:
instances: 1
primaryUpdateStrategy: unsupervised

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: redis-config
data:
redis-url: redis-service

View File

@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: redis-deployment
spec:
replicas: 1
@@ -15,7 +15,7 @@ spec:
spec:
containers:
- name: redis
image: bitnami/redis
image: bitnami/redis:6.2.16
imagePullPolicy: "IfNotPresent"
resources:
requests:
@@ -37,7 +37,7 @@ spec:
apiVersion: v1
kind: Service
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: redis-service
spec:
selector:

View File

@@ -1,7 +1,7 @@
apiVersion: v1
kind: ConfigMap
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: storage-config
data:
storage_url: storage-service

View File

@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: storage-processor-deployment
spec:
replicas: 1
@@ -44,13 +44,13 @@ spec:
valueFrom:
secretKeyRef:
name: frontend-secret
key: backendUrl
key: frontendBackendUrl
- name: EXPIRES_IN
valueFrom:
secretKeyRef:
name: backend-secret
key: accessTokenDuration
key: backendAccessTokenDuration
- name: SERVER_PORT
valueFrom:
@@ -86,34 +86,34 @@ spec:
valueFrom:
secretKeyRef:
name: storage-secret
key: awsAccessKeyId
key: storageAwsAccessKeyId
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: storage-secret
key: awsSecretAccessKey
key: storageAwsSecretAccessKey
- name: AWS_REGION_NAME
valueFrom:
secretKeyRef:
name: storage-secret
key: awsRegion
key: storageAwsRegion
- name: AWS_BUCKET_NAME
valueFrom:
secretKeyRef:
name: storage-secret
key: awsBucket
key: storageAwsBucket
- name: VIRUS_CHECKER_TYPE
valueFrom:
secretKeyRef:
name: storage-secret
key: virusCheckerType
key: storageVirusCheckerType
- name: VIRUS_CHECKER_API_KEY
valueFrom:
secretKeyRef:
name: storage-secret
key: virusCheckerApiKey
key: storageVirusCheckerApiKey

View File

@@ -1,7 +1,7 @@
apiVersion: apps/v1
kind: Deployment
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: storage-deployment
spec:
replicas: 1
@@ -43,13 +43,13 @@ spec:
valueFrom:
secretKeyRef:
name: frontend-secret
key: backendUrl
key: frontendBackendUrl
- name: EXPIRES_IN
valueFrom:
secretKeyRef:
name: backend-secret
key: accessTokenDuration
key: backendAccessTokenDuration
- name: SERVER_PORT
valueFrom:
@@ -85,43 +85,43 @@ spec:
valueFrom:
secretKeyRef:
name: storage-secret
key: awsAccessKeyId
key: storageAwsAccessKeyId
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: storage-secret
key: awsSecretAccessKey
key: storageAwsSecretAccessKey
- name: AWS_REGION_NAME
valueFrom:
secretKeyRef:
name: storage-secret
key: awsRegion
key: storageAwsRegion
- name: AWS_BUCKET_NAME
valueFrom:
secretKeyRef:
name: storage-secret
key: awsBucket
key: storageAwsBucket
- name: VIRUS_CHECKER_TYPE
valueFrom:
secretKeyRef:
name: storage-secret
key: virusCheckerType
key: storageVirusCheckerType
- name: VIRUS_CHECKER_API_KEY
valueFrom:
secretKeyRef:
name: storage-secret
key: virusCheckerApiKey
key: storageVirusCheckerApiKey
---
apiVersion: v1
kind: Service
metadata:
namespace: portfolio
namespace: ${KUBE_NAMESPACE}
name: storage-service
spec:
selector: