From abe800dd5e3f14802f172b94d1bb06c0dd96b3de Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Mon, 14 Oct 2024 02:36:17 -0300 Subject: [PATCH 01/13] Initial Implementation of Better Deployment This branch basically removes the necessity of a setup script and just deploys --- .env.example | 39 ++++ .gitignore | 1 + Pipfile | 13 -- Pipfile.lock | 37 ---- deploy.sh | 189 +++++-------------- refresh.sh | 47 ----- setup.py | 208 --------------------- template/portfolio-namespace.template.yaml | 4 + template/portfolio-secret.template.yml | 77 ++++++++ 9 files changed, 170 insertions(+), 445 deletions(-) create mode 100644 .env.example delete mode 100644 Pipfile delete mode 100644 Pipfile.lock delete mode 100755 refresh.sh delete mode 100644 setup.py create mode 100644 template/portfolio-namespace.template.yaml create mode 100644 template/portfolio-secret.template.yml diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..ed874d7 --- /dev/null +++ b/.env.example @@ -0,0 +1,39 @@ +KUBE_NAMESPACE= + +# 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= diff --git a/.gitignore b/.gitignore index d48d751..af4bec9 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .vscode/ .env* +!.env.example .secret* **/*.json diff --git a/Pipfile b/Pipfile deleted file mode 100644 index 70e71ab..0000000 --- a/Pipfile +++ /dev/null @@ -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" diff --git a/Pipfile.lock b/Pipfile.lock deleted file mode 100644 index 6f0e098..0000000 --- a/Pipfile.lock +++ /dev/null @@ -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": {} -} diff --git a/deploy.sh b/deploy.sh index 336a9f3..8031b3f 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,154 +1,63 @@ -#!/bin/bash +#!/bin/sh -function check_for_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 - echo "helm could not be found" - exit 1 +# eval "$(awk 'BEGIN{ +# for (i in ENVIRON) { +# if (i ~ /^(KUBE_)[a-zA-Z_][a-zA-Z0-9_]*$/) { +# printf "export " i "_B64="; +# system("echo \"$"i"\" | base64 -w0"); +# print; +# } +# } +# }' /dev/null)" + + +function read_env_file() { + if [[ -f $1 ]]; then + set -a && source $1 && set +a; fi } -function configure_nginx_ingress() { - helm upgrade --install ingress-nginx ingress-nginx \ - --repo https://kubernetes.github.io/ingress-nginx \ - --namespace ingress-nginx --create-namespace - kubectl wait --namespace ingress-nginx \ - --for=condition=ready pod \ - --selector=app.kubernetes.io/component=controller \ - --timeout=120s +function 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 ${!i} | base64 -w0)" + done } -function configure_cert_manager() { - helm repo add jetstack https://charts.jetstack.io --force-update - helm repo update - helm install cert-manager jetstack/cert-manager \ - --namespace cert-manager \ - --create-namespace \ - --version v1.14.2 \ - --set installCRDs=true \ - --timeout=600s + +function deploy_kubernetes() { + KUBE_FILES=( + "./template/portfolio-namespace.template.yaml" + "./template/portfolio-secret.template.yml" + ) + + for file in ${KUBE_FILES[@]}; do + echo -e "\n\n----------------------------------------------------\n" + echo -e "Deploying: $file\n" + echo -e "----------------------------------------------------\n\n\n" + + envsubst < $file + done } -function configure_postgres() { - helm repo add cnpg https://cloudnative-pg.github.io/charts - helm upgrade --install cnpg \ - --namespace portfolio \ - --create-namespace \ - cnpg/cloudnative-pg - - kubectl wait --for=condition=available \ - --timeout=600s \ - deployment.apps/cnpg-cloudnative-pg \ - -n portfolio - - kubectl apply -f ./deployment/postgres/cn-cluster.yaml - kubectl wait --for=condition=Ready \ - --timeout=600s \ - cluster/postgres-cn-cluster \ - -n portfolio -} - -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() { + build_secret_envs - 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 - - else - - configure_nginx_ingress - - fi - - configure_cert_manager - - kubectl apply -f ./deployment/portfolio-namespace.yaml - - configure_postgres - - application_deploy - - if [[ $1 == "--local" || $1 == "-l" ]]; then - - kubectl apply -f \ - ./deployment/cert-manager/cert-manager-issuer-dev.yaml - - kubectl apply -f \ - ./deployment/cert-manager/cert-manager-certificate.yaml - - 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 - - fi - - exit 0 - + deploy_kubernetes } -main $1 + +while getopts ":f:" opt; do + case ${opt} in + f ) + echo "Reading env file: ${OPTARG}" + read_env_file ${OPTARG} + ;; + \? ) + echo "Usage: deploy.sh [-f ]" + ;; + esac +done + +main \ No newline at end of file diff --git a/refresh.sh b/refresh.sh deleted file mode 100755 index 7e905c2..0000000 --- a/refresh.sh +++ /dev/null @@ -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[@]}" - diff --git a/setup.py b/setup.py deleted file mode 100644 index 1769c86..0000000 --- a/setup.py +++ /dev/null @@ -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)) diff --git a/template/portfolio-namespace.template.yaml b/template/portfolio-namespace.template.yaml new file mode 100644 index 0000000..f068a10 --- /dev/null +++ b/template/portfolio-namespace.template.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: ${KUBE_NAMESPACE} \ No newline at end of file diff --git a/template/portfolio-secret.template.yml b/template/portfolio-secret.template.yml new file mode 100644 index 0000000..c27d3fd --- /dev/null +++ b/template/portfolio-secret.template.yml @@ -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} + \ No newline at end of file From c1b2deaa6ef3477a6d9acfb4e540d5a58fa92649 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 00:10:00 -0300 Subject: [PATCH 02/13] First Complete Working Version --- deploy.sh | 153 ++++++++++++++---- deployment/portfolio-namespace.yaml | 4 - .../backend/backend-config.yaml | 4 +- template/backend/backend.template.yaml | 32 ++-- .../cert-manager-certificate.template.yaml | 8 +- .../cert-manager/cert-manager-issuer-dev.yaml | 0 .../cert-manager/cert-manager-issuer.yaml | 4 +- .../frontend/frontend-config.yaml | 2 +- template/frontend/frontend.template.yaml | 10 +- .../nginx-ingress-root.template.yaml | 10 +- template/postgres/cn-cluster.template.yaml | 2 +- .../redis/redis-config.yaml | 2 +- {deployment => template}/redis/redis.yaml | 6 +- .../storage/storage-config.yaml | 2 +- .../storage/storage-processor.template.yaml | 18 +-- template/storage/storage.template.yaml | 20 +-- 16 files changed, 186 insertions(+), 91 deletions(-) delete mode 100644 deployment/portfolio-namespace.yaml rename {deployment => template}/backend/backend-config.yaml (63%) rename {deployment => template}/cert-manager/cert-manager-issuer-dev.yaml (100%) rename {deployment => template}/cert-manager/cert-manager-issuer.yaml (73%) rename {deployment => template}/frontend/frontend-config.yaml (76%) rename {deployment => template}/redis/redis-config.yaml (77%) rename {deployment => template}/redis/redis.yaml (90%) rename {deployment => template}/storage/storage-config.yaml (79%) diff --git a/deploy.sh b/deploy.sh index 8031b3f..5776f34 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,63 +1,162 @@ #!/bin/sh -# eval "$(awk 'BEGIN{ -# for (i in ENVIRON) { -# if (i ~ /^(KUBE_)[a-zA-Z_][a-zA-Z0-9_]*$/) { -# printf "export " i "_B64="; -# system("echo \"$"i"\" | base64 -w0"); -# print; -# } -# } -# }' /dev/null)" - -function read_env_file() { - if [[ -f $1 ]]; then +read_env_file() { + if [ -f $1 ]; then set -a && source $1 && set +a; fi } -function build_secret_envs() { +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 ${!i} | base64 -w0)" + eval "export ${i}_B64=$(echo -n ${!i} | base64 -w0)" done } -function deploy_kubernetes() { +apply_template() { + echo -e "\n\n----------------------------------------------------\n" + echo -e "Applying: $1\n" + echo -e "----------------------------------------------------\n\n\n" + + envsubst < $1 | kubectl apply -f - +} + + +apply_deployment() { + for file in $(find $1 -type f); do + apply_template $file + done +} + + +configure_nginx_minikube() { + if [[ $1 == "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 + + kubectl wait --namespace ingress-nginx \ + --for=condition=ready pod \ + --selector=app.kubernetes.io/component=controller \ + --timeout=120s +} + + +configure_cert_manager() { + helm repo add jetstack https://charts.jetstack.io --force-update + helm repo update + helm install cert-manager jetstack/cert-manager \ + --namespace cert-manager \ + --create-namespace \ + --version v1.14.2 \ + --set installCRDs=true \ + --timeout=600s || echo "Cert Manager already installed" +} + + +configure_postgres() { + helm repo add cnpg https://cloudnative-pg.github.io/charts + helm upgrade --install cnpg \ + --namespace ${KUBE_NAMESPACE} \ + --create-namespace \ + cnpg/cloudnative-pg + + kubectl wait --for=condition=available \ + --timeout=600s \ + deployment.apps/cnpg-cloudnative-pg \ + -n ${KUBE_NAMESPACE} + + apply_template "./template/postgres/cn-cluster.template.yaml" + kubectl wait --for=condition=Ready \ + --timeout=600s \ + cluster/postgres-cn-cluster \ + -n ${KUBE_NAMESPACE} +} + + +configure_ingress() { + apply_template "./template/nginx-ingress/nginx-ingress-root.template.yaml" + + if [[ $1 == "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 [[ $1 == "local" ]]; then + configure_nginx_minikube $2 + else + configure_nginx_ingress + fi + + configure_cert_manager + KUBE_FILES=( "./template/portfolio-namespace.template.yaml" "./template/portfolio-secret.template.yml" ) for file in ${KUBE_FILES[@]}; do - echo -e "\n\n----------------------------------------------------\n" - echo -e "Deploying: $file\n" - echo -e "----------------------------------------------------\n\n\n" - - envsubst < $file + apply_template $file done + + configure_postgres + + apply_deployment "./template/redis" + + apply_deployment "./template/frontend" + + apply_deployment "./template/storage" + + apply_deployment "./template/backend" + + configure_ingress $1 } -function main() { +main() { build_secret_envs - deploy_kubernetes + deploy_kubernetes $@ } -while getopts ":f:" opt; do +environment="remote" +setup_minikube="false" + +while getopts ":f:e:m:h:" opt; do case ${opt} in - f ) + f) echo "Reading env file: ${OPTARG}" read_env_file ${OPTARG} ;; - \? ) - echo "Usage: deploy.sh [-f ]" + e) + [[ ${OPTARG} == "local" ]] && environment="local" + ;; + m) + setup_minikube="true" + ;; + *) + echo "Usage: deploy.sh [-f ] [-e ] [-m ]" + exit 1 ;; esac done -main \ No newline at end of file +main $environment $setup_minikube \ No newline at end of file diff --git a/deployment/portfolio-namespace.yaml b/deployment/portfolio-namespace.yaml deleted file mode 100644 index 5b9aa57..0000000 --- a/deployment/portfolio-namespace.yaml +++ /dev/null @@ -1,4 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: portfolio \ No newline at end of file diff --git a/deployment/backend/backend-config.yaml b/template/backend/backend-config.yaml similarity index 63% rename from deployment/backend/backend-config.yaml rename to template/backend/backend-config.yaml index f8b54f6..126b9b6 100644 --- a/deployment/backend/backend-config.yaml +++ b/template/backend/backend-config.yaml @@ -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 \ No newline at end of file + backend_db_name: ${KUBE_DATABASE_NAME} \ No newline at end of file diff --git a/template/backend/backend.template.yaml b/template/backend/backend.template.yaml index 1bb8548..b86482f 100644 --- a/template/backend/backend.template.yaml +++ b/template/backend/backend.template.yaml @@ -1,7 +1,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: backend-deployment spec: replicas: 1 @@ -43,49 +43,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 +97,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 +193,7 @@ spec: apiVersion: v1 kind: Service metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: backend-service spec: selector: diff --git a/template/cert-manager/cert-manager-certificate.template.yaml b/template/cert-manager/cert-manager-certificate.template.yaml index 09d5a1b..7a25aa8 100644 --- a/template/cert-manager/cert-manager-certificate.template.yaml +++ b/template/cert-manager/cert-manager-certificate.template.yaml @@ -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 \ No newline at end of file + - ${KUBE_DOMAIN_ORGANIZATION} \ No newline at end of file diff --git a/deployment/cert-manager/cert-manager-issuer-dev.yaml b/template/cert-manager/cert-manager-issuer-dev.yaml similarity index 100% rename from deployment/cert-manager/cert-manager-issuer-dev.yaml rename to template/cert-manager/cert-manager-issuer-dev.yaml diff --git a/deployment/cert-manager/cert-manager-issuer.yaml b/template/cert-manager/cert-manager-issuer.yaml similarity index 73% rename from deployment/cert-manager/cert-manager-issuer.yaml rename to template/cert-manager/cert-manager-issuer.yaml index 6936556..de0159f 100644 --- a/deployment/cert-manager/cert-manager-issuer.yaml +++ b/template/cert-manager/cert-manager-issuer.yaml @@ -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: diff --git a/deployment/frontend/frontend-config.yaml b/template/frontend/frontend-config.yaml similarity index 76% rename from deployment/frontend/frontend-config.yaml rename to template/frontend/frontend-config.yaml index c8bf709..7ca5d0b 100644 --- a/deployment/frontend/frontend-config.yaml +++ b/template/frontend/frontend-config.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: frontend-config data: frontend_url: frontend-service \ No newline at end of file diff --git a/template/frontend/frontend.template.yaml b/template/frontend/frontend.template.yaml index 614619c..f092690 100644 --- a/template/frontend/frontend.template.yaml +++ b/template/frontend/frontend.template.yaml @@ -1,7 +1,7 @@ apiVersion: apps/v1 kind: Deployment metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: frontend-deployment labels: app: frontend @@ -47,23 +47,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: diff --git a/template/nginx-ingress/nginx-ingress-root.template.yaml b/template/nginx-ingress/nginx-ingress-root.template.yaml index e752f56..64bd92d 100644 --- a/template/nginx-ingress/nginx-ingress-root.template.yaml +++ b/template/nginx-ingress/nginx-ingress-root.template.yaml @@ -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: / diff --git a/template/postgres/cn-cluster.template.yaml b/template/postgres/cn-cluster.template.yaml index 0ce2949..f53bffb 100644 --- a/template/postgres/cn-cluster.template.yaml +++ b/template/postgres/cn-cluster.template.yaml @@ -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 diff --git a/deployment/redis/redis-config.yaml b/template/redis/redis-config.yaml similarity index 77% rename from deployment/redis/redis-config.yaml rename to template/redis/redis-config.yaml index a63391a..cd08cc9 100644 --- a/deployment/redis/redis-config.yaml +++ b/template/redis/redis-config.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: redis-config data: redis-url: redis-service diff --git a/deployment/redis/redis.yaml b/template/redis/redis.yaml similarity index 90% rename from deployment/redis/redis.yaml rename to template/redis/redis.yaml index 52908d9..93a1f40 100644 --- a/deployment/redis/redis.yaml +++ b/template/redis/redis.yaml @@ -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: diff --git a/deployment/storage/storage-config.yaml b/template/storage/storage-config.yaml similarity index 79% rename from deployment/storage/storage-config.yaml rename to template/storage/storage-config.yaml index 229d64e..e3b0228 100644 --- a/deployment/storage/storage-config.yaml +++ b/template/storage/storage-config.yaml @@ -1,7 +1,7 @@ apiVersion: v1 kind: ConfigMap metadata: - namespace: portfolio + namespace: ${KUBE_NAMESPACE} name: storage-config data: storage_url: storage-service diff --git a/template/storage/storage-processor.template.yaml b/template/storage/storage-processor.template.yaml index 9677924..becbd58 100644 --- a/template/storage/storage-processor.template.yaml +++ b/template/storage/storage-processor.template.yaml @@ -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 diff --git a/template/storage/storage.template.yaml b/template/storage/storage.template.yaml index 9e10e0e..a408161 100644 --- a/template/storage/storage.template.yaml +++ b/template/storage/storage.template.yaml @@ -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: From af426a72e985f5d243db51cb3043e1756871b892 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 00:25:03 -0300 Subject: [PATCH 03/13] Better CLI Options --- deploy.sh | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/deploy.sh b/deploy.sh index 5776f34..c740a4e 100755 --- a/deploy.sh +++ b/deploy.sh @@ -32,7 +32,7 @@ apply_deployment() { configure_nginx_minikube() { - if [[ $1 == "true" ]]; then + if [[ $setup_minikube == "true" ]]; then minikube start --driver kvm2 --cpus 2 --memory 4Gib fi @@ -88,7 +88,7 @@ configure_postgres() { configure_ingress() { apply_template "./template/nginx-ingress/nginx-ingress-root.template.yaml" - if [[ $1 == "local" ]]; then + if [[ $environment == "local" ]]; then apply_template "./template/cert-manager/cert-manager-issuer-dev.yaml" else apply_template "./template/cert-manager/cert-manager-issuer.yaml" @@ -99,8 +99,8 @@ configure_ingress() { deploy_kubernetes() { - if [[ $1 == "local" ]]; then - configure_nginx_minikube $2 + if [[ $environment == "local" ]]; then + configure_nginx_minikube else configure_nginx_ingress fi @@ -126,7 +126,7 @@ deploy_kubernetes() { apply_deployment "./template/backend" - configure_ingress $1 + configure_ingress } @@ -140,23 +140,29 @@ main() { environment="remote" setup_minikube="false" -while getopts ":f:e:m:h:" opt; do +while getopts ":f:e:mh" opt; do case ${opt} in - f) + f ) echo "Reading env file: ${OPTARG}" read_env_file ${OPTARG} ;; - e) + e ) [[ ${OPTARG} == "local" ]] && environment="local" + echo "Environment: ${OPTARG}" ;; - m) + m ) setup_minikube="true" + echo "Setting up minikube" + ;; + h ) + echo "Usage: deploy.sh [-f ] [-e ] [-m ]" + exit 0 ;; *) - echo "Usage: deploy.sh [-f ] [-e ] [-m ]" + echo "Invalid option: $OPTARG" exit 1 ;; esac done -main $environment $setup_minikube \ No newline at end of file +main \ No newline at end of file From 7a65a62cf65528af447a68fb155998186edffccb Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 03:28:07 -0300 Subject: [PATCH 04/13] Adds Minikube IP to Local Run --- deploy.sh | 4 ++++ template/backend/backend.template.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/deploy.sh b/deploy.sh index c740a4e..f954881 100755 --- a/deploy.sh +++ b/deploy.sh @@ -127,6 +127,10 @@ deploy_kubernetes() { apply_deployment "./template/backend" configure_ingress + + if [[ $environment == "local" ]]; then + echo "Minikube IP: http://$(minikube ip)" + fi } diff --git a/template/backend/backend.template.yaml b/template/backend/backend.template.yaml index b86482f..eb3444a 100644 --- a/template/backend/backend.template.yaml +++ b/template/backend/backend.template.yaml @@ -32,7 +32,7 @@ spec: httpGet: path: /health port: 8070 - initialDelaySeconds: 240 + initialDelaySeconds: 120 livenessProbe: httpGet: path: /health From f7844975e5e6c59fec5ab3234168c5971f0b2ca4 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 04:36:15 -0300 Subject: [PATCH 05/13] Implements Waiting for Deployments to Finish --- deploy.sh | 18 +++++++++++++----- template/backend/backend.template.yaml | 14 +++++++++++++- template/frontend/frontend.template.yaml | 11 +++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/deploy.sh b/deploy.sh index f954881..0f0df8e 100755 --- a/deploy.sh +++ b/deploy.sh @@ -25,9 +25,17 @@ apply_template() { apply_deployment() { - for file in $(find $1 -type f); do + 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} } @@ -118,13 +126,13 @@ deploy_kubernetes() { configure_postgres - apply_deployment "./template/redis" + apply_deployment "redis-deployment" "./template/redis" - apply_deployment "./template/frontend" + apply_deployment "storage-deployment" "./template/storage" - apply_deployment "./template/storage" + apply_deployment "backend-deployment" "./template/backend" - apply_deployment "./template/backend" + apply_deployment "frontend-deployment" "./template/frontend" configure_ingress diff --git a/template/backend/backend.template.yaml b/template/backend/backend.template.yaml index eb3444a..d38c2ad 100644 --- a/template/backend/backend.template.yaml +++ b/template/backend/backend.template.yaml @@ -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: 120 + initialDelaySeconds: 60 livenessProbe: httpGet: path: /health diff --git a/template/frontend/frontend.template.yaml b/template/frontend/frontend.template.yaml index f092690..b71ccbd 100644 --- a/template/frontend/frontend.template.yaml +++ b/template/frontend/frontend.template.yaml @@ -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 From 7075e86a26590723033523ccff65998d827d575d Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 23:19:04 -0300 Subject: [PATCH 06/13] Inicia Implementacao de Refresh --- .github/workflows/deploy-cluster.yml | 30 ++++++++++++++ .github/workflows/deploy-prod.yml | 58 ---------------------------- .github/workflows/deploy-staging.yml | 56 --------------------------- deploy.sh | 18 ++++++++- 4 files changed, 47 insertions(+), 115 deletions(-) create mode 100644 .github/workflows/deploy-cluster.yml delete mode 100644 .github/workflows/deploy-prod.yml delete mode 100644 .github/workflows/deploy-staging.yml diff --git a/.github/workflows/deploy-cluster.yml b/.github/workflows/deploy-cluster.yml new file mode 100644 index 0000000..647e6c2 --- /dev/null +++ b/.github/workflows/deploy-cluster.yml @@ -0,0 +1,30 @@ +name: remote ssh command + +on: + repository_dispatch: + types: [deploy-prod] + push: + branches: + - main + - staging + +jobs: + build: + 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 \ No newline at end of file diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml deleted file mode 100644 index d1a7e2a..0000000 --- a/.github/workflows/deploy-prod.yml +++ /dev/null @@ -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 \ No newline at end of file diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml deleted file mode 100644 index 520ab1e..0000000 --- a/.github/workflows/deploy-staging.yml +++ /dev/null @@ -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 diff --git a/deploy.sh b/deploy.sh index 0f0df8e..e1b9eab 100755 --- a/deploy.sh +++ b/deploy.sh @@ -149,8 +149,13 @@ main() { } +refresh() { +} + + environment="remote" setup_minikube="false" +execution_mode="deploy" while getopts ":f:e:mh" opt; do case ${opt} in @@ -170,6 +175,10 @@ while getopts ":f:e:mh" opt; do echo "Usage: deploy.sh [-f ] [-e ] [-m ]" exit 0 ;; + r ) + echo "Executing Refresh" + execution_mode="refresh" + ;; *) echo "Invalid option: $OPTARG" exit 1 @@ -177,4 +186,11 @@ while getopts ":f:e:mh" opt; do esac done -main \ No newline at end of file +if [[ $execution_mode == "deploy" ]]; then + main +elif [[ $execution_mode == "refresh" ]]; then + refresh +else + echo "Invalid execution mode: $execution_mode" + exit 1 +fi \ No newline at end of file From 39b72a482f7bd3bc1cc6712ca6f01f254843bf8c Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 23:21:30 -0300 Subject: [PATCH 07/13] Remove env.json --- env.example.json | 39 --------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 env.example.json diff --git a/env.example.json b/env.example.json deleted file mode 100644 index 1533946..0000000 --- a/env.example.json +++ /dev/null @@ -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": "" - } -} \ No newline at end of file From 4d69fedc81f8f5a81d2a29f70830293cb056b0ad Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Wed, 16 Oct 2024 23:22:53 -0300 Subject: [PATCH 08/13] Adds New Envs to Example --- .env.example | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.env.example b/.env.example index ed874d7..9d15f5e 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,15 @@ 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= From 6eb74bbdb735de4b32a429372dd1eac6936b6166 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Fri, 18 Oct 2024 01:37:52 -0300 Subject: [PATCH 09/13] Initial Implementation of Refresh Cluster --- .github/workflows/deploy-cluster.yml | 2 +- .github/workflows/refresh-deployment.yml | 52 ++++++++++-------------- deploy.sh | 22 +++++++++- 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/.github/workflows/deploy-cluster.yml b/.github/workflows/deploy-cluster.yml index 647e6c2..e295175 100644 --- a/.github/workflows/deploy-cluster.yml +++ b/.github/workflows/deploy-cluster.yml @@ -9,7 +9,7 @@ on: - staging jobs: - build: + deploy: name: Deploy to Cluster environment: ${{ github.ref_name == 'main' && 'prod' || 'staging' }} runs-on: ubuntu-latest diff --git a/.github/workflows/refresh-deployment.yml b/.github/workflows/refresh-deployment.yml index 36adfc7..3df41d6 100644 --- a/.github/workflows/refresh-deployment.yml +++ b/.github/workflows/refresh-deployment.yml @@ -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: Set Kubernetes Context + uses: azure/k8s-set-context@v1 + with: + method: kubeconfig + kubeconfig: ${{ secrets.KUBE_CONFIG }} - - name: Executing Remote Commands - Refresh All Deployments - env: - deployments: ${{ github.event.client_payload.deployments }} + - 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 }} \ No newline at end of file + run: | + ./deploy.sh -f .env -r ${{ env.deployments }} \ No newline at end of file diff --git a/deploy.sh b/deploy.sh index e1b9eab..e61dc3f 100755 --- a/deploy.sh +++ b/deploy.sh @@ -150,6 +150,18 @@ main() { 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 } @@ -157,7 +169,7 @@ environment="remote" setup_minikube="false" execution_mode="deploy" -while getopts ":f:e:mh" opt; do +while getopts ":f:e:mrh" opt; do case ${opt} in f ) echo "Reading env file: ${OPTARG}" @@ -178,6 +190,12 @@ while getopts ":f:e:mh" opt; do 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" @@ -189,7 +207,7 @@ done if [[ $execution_mode == "deploy" ]]; then main elif [[ $execution_mode == "refresh" ]]; then - refresh + [[ -z $refresh_deployments ]] && refresh || refresh $refresh_deployments else echo "Invalid execution mode: $execution_mode" exit 1 From f712973df9ff23e1933d4267396fe465140b27ed Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 20 Oct 2024 22:20:39 -0300 Subject: [PATCH 10/13] Adds KUBECONFIG Files to GitIgnore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index af4bec9..1ea70ac 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ !**/*.example.json *.patch +*KUBECONFIG* + **/cert-manager-certificate.yaml **/nginx-ingress-api.yaml **/nginx-ingress-root.yaml From e1350f0812b3e8491b3aa12ad331aae0bc5c9407 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 20 Oct 2024 22:30:31 -0300 Subject: [PATCH 11/13] Implements Validation of Dependencies --- deploy.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/deploy.sh b/deploy.sh index e61dc3f..c802636 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,6 +1,33 @@ #!/bin/sh +validate_dependencies() { + if ! command -v kubectl &> /dev/null; then + echo "kubectl could not be found" + exit 1 + fi + + 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" +} + + read_env_file() { if [ -f $1 ]; then set -a && source $1 && set +a; @@ -204,6 +231,8 @@ while getopts ":f:e:mrh" opt; do esac done +validate_dependencies + if [[ $execution_mode == "deploy" ]]; then main elif [[ $execution_mode == "refresh" ]]; then From 44b4862e6d5c89915582fc5476ed33024fb14042 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 20 Oct 2024 22:33:59 -0300 Subject: [PATCH 12/13] Fixes Kubeconfig Variable Pipeline --- .github/workflows/deploy-cluster.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-cluster.yml b/.github/workflows/deploy-cluster.yml index e295175..ec73f11 100644 --- a/.github/workflows/deploy-cluster.yml +++ b/.github/workflows/deploy-cluster.yml @@ -24,7 +24,7 @@ jobs: uses: azure/k8s-set-context@v1 with: method: kubeconfig - kubeconfig: ${{ secrets.KUBE_CONFIG }} + kubeconfig: ${{ secrets.KUBECONFIG }} - name: Execute deploy run: | ./deploy.sh -f .env \ No newline at end of file From 7d8b70ed419d032caa6e6471b843d97972e395a7 Mon Sep 17 00:00:00 2001 From: Vitor Hideyoshi Date: Sun, 20 Oct 2024 22:38:27 -0300 Subject: [PATCH 13/13] Adds Better Script shebang --- deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.sh b/deploy.sh index c802636..023bc15 100755 --- a/deploy.sh +++ b/deploy.sh @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash validate_dependencies() {