diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 8ded8f5bb..256a4502b 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -16,7 +16,7 @@ on: - .github/workflows/continuous-integration.yml schedule: # Sunday at 2 PM UTC (Sunday afternoon) - - cron: '0 14 * * 0' + - cron: "0 14 * * 0" env: PR_NUMBER: ${{ github.event.number }} @@ -28,7 +28,7 @@ concurrency: jobs: check-recording-bot-changes: runs-on: ubuntu-latest - outputs: + outputs: build: ${{ steps.changes.outputs.build }} deploy: ${{ steps.changes.outputs.deploy }} docs: ${{ steps.changes.outputs.docs }} @@ -85,21 +85,21 @@ jobs: defaults: run: working-directory: deploy - + outputs: app-version-check-passed: ${{ steps.app-version-check.outcome }} chart-version-check-passed: ${{ steps.chart-version-check.outcome }} - + steps: - uses: actions/checkout@v4 - run: | - git fetch - git branch -a + git fetch + git branch -a - name: Install Helm uses: azure/setup-helm@v3 with: - version: 'latest' + version: "latest" - name: Lint Helm Chart working-directory: deploy/teams-recording-bot @@ -120,39 +120,39 @@ jobs: ) shell: bash run: | - echo "🔍 Checking app version changes..." - oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p") - echo "Previous app Version: $oldVersion" - [ -z "$oldVersion" ] && exit 1 + echo "🔍 Checking app version changes..." + oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p") + echo "Previous app Version: $oldVersion" + [ -z "$oldVersion" ] && exit 1 - newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p") - echo "New app Version: $newVersion" - [ -z "$newVersion" ] && exit 1 + newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^appVersion: \([0-9\.]*\)$/\1/p") + echo "New app Version: $newVersion" + [ -z "$newVersion" ] && exit 1 - echo "Check if app Version was updated" - [ "$newVersion" = "$oldVersion" ] && exit 1 - newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1) - [ "$newerVersion" = "$newVersion" ] || exit 1 - echo "✅ Success app Version was updated!" + echo "Check if app Version was updated" + [ "$newVersion" = "$oldVersion" ] && exit 1 + newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1) + [ "$newerVersion" = "$newVersion" ] || exit 1 + echo "✅ Success app Version was updated!" - name: Check Chart Version Change (PR only) if: github.event_name == 'pull_request' && needs.check-recording-bot-changes.outputs.deploy == 'True' shell: bash run: | - echo "🔍 Checking chart version changes..." - oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^version: \([0-9\.]*\)$/\1/p") - echo "Previous Version: $oldVersion" - [ -z "$oldVersion" ] && exit 1 - - newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^version: \([0-9\.]*\)$/\1/p") - echo "New Version: $newVersion" - [ -z "$newVersion" ] && exit 1 - - echo "Check if Version was updated" - [ "$newVersion" = "$oldVersion" ] && exit 1 - newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1) - [ "$newerVersion" = "$newVersion" ] || exit 1 - echo "✅ Success Version was updated!" + echo "🔍 Checking chart version changes..." + oldVersion=$(MSYS_NO_PATHCONV=1 git show remotes/origin/$GITHUB_BASE_REF:deploy/teams-recording-bot/Chart.yaml | sed -n "s/^version: \([0-9\.]*\)$/\1/p") + echo "Previous Version: $oldVersion" + [ -z "$oldVersion" ] && exit 1 + + newVersion=$(cat teams-recording-bot/Chart.yaml | sed -n "s/^version: \([0-9\.]*\)$/\1/p") + echo "New Version: $newVersion" + [ -z "$newVersion" ] && exit 1 + + echo "Check if Version was updated" + [ "$newVersion" = "$oldVersion" ] && exit 1 + newerVersion=$(echo -e "$oldVersion\n$newVersion" | sort -V | tail -1) + [ "$newerVersion" = "$newVersion" ] || exit 1 + echo "✅ Success Version was updated!" start-cluster: needs: [check-recording-bot-changes, chart-version-checks] @@ -166,11 +166,11 @@ jobs: ) uses: ./.github/workflows/routine-managecluster.yml with: - action: 'start' + action: "start" cluster-name: ${{ vars.AKS_CLUSTER_NAME }} resource-group: ${{ vars.AKS_RESOURCE_GROUP }} subscription: ${{ vars.AZURE_SUBSCRIPTION_ID }} - secrets: + secrets: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} generate-image-tag: @@ -179,15 +179,15 @@ jobs: needs.chart-version-checks.result == 'success' && ( needs.check-recording-bot-changes.outputs.build == 'True' || - needs.check-recording-bot-changes.outputs.src == 'True' || - needs.check-recording-bot-changes.outputs.scripts == 'True' + needs.check-recording-bot-changes.outputs.deploy == 'True' || + needs.check-recording-bot-changes.outputs.scripts == 'True' || + needs.check-recording-bot-changes.outputs.src == 'True' ) runs-on: ubuntu-latest - outputs: image-tag: ${{ steps.generate-tag.outputs.tag }} image-exists: ${{ steps.check-image.outputs.image-exists }} - + steps: - uses: actions/checkout@v4 @@ -197,29 +197,44 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - + - name: Generate content-based image tag id: generate-tag run: | - hash=$(find src build scripts -type f -exec sha256sum {} \; | sort | sha256sum | awk '{print $1}') - if [ '${{ github.event_name }}' = 'pull_request' ]; then - echo "tag=pr-${{ github.event.number }}-${hash:0:8}" >> $GITHUB_OUTPUT + hash=$(find src build scripts -type f -exec sha256sum {} \; | sort | sha256sum | awk '{print $1}') + base_tag=${hash:0:8} + + if [ '${{ github.event_name }}' = 'pull_request' ]; then + # For PRs, first check if the base hash (main branch) image exists + if docker manifest inspect ${{ vars.CR_NAMESPACE_REPOSITORY }}:${base_tag} > /dev/null 2>&1; then + echo "✅ Found existing image for hash ${base_tag}, reusing for PR" + echo "tag=${base_tag}" >> $GITHUB_OUTPUT + echo "reused-main-image=true" >> $GITHUB_OUTPUT else - echo "tag=${hash:0:8}" >> $GITHUB_OUTPUT + echo "❌ No existing image for hash ${base_tag}, will build PR-specific image" + pr_tag="pr-${{ github.event.number }}-${base_tag}" + echo "tag=${pr_tag}" >> $GITHUB_OUTPUT + echo "reused-main-image=false" >> $GITHUB_OUTPUT fi + else + echo "tag=${base_tag}" >> $GITHUB_OUTPUT + echo "reused-main-image=false" >> $GITHUB_OUTPUT + fi - name: Check if image exists id: check-image run: | if docker manifest inspect ${{ vars.CR_NAMESPACE_REPOSITORY }}:${{ steps.generate-tag.outputs.tag }} > /dev/null 2>&1; then - echo "Image already exists" + echo "Image already exists: ${{ steps.generate-tag.outputs.tag }}" echo "image-exists=true" >> $GITHUB_OUTPUT else + echo "Image does not exist: ${{ steps.generate-tag.outputs.tag }}" echo "image-exists=false" >> $GITHUB_OUTPUT fi build-docker-image: - needs: [check-recording-bot-changes, chart-version-checks, generate-image-tag] + needs: + [check-recording-bot-changes, chart-version-checks, generate-image-tag] if: | needs.chart-version-checks.result == 'success' && ( @@ -237,7 +252,14 @@ jobs: secrets: inherit deploy-to-environment: - needs: [check-recording-bot-changes, chart-version-checks, start-cluster, build-docker-image, generate-image-tag] + needs: + [ + check-recording-bot-changes, + chart-version-checks, + start-cluster, + build-docker-image, + generate-image-tag, + ] if: | always() && needs.start-cluster.result == 'success' && @@ -249,7 +271,7 @@ jobs: uses: ./.github/workflows/routine-deployenvironment.yml with: environment-name: aks-sample - port: '28550' + port: "28550" cluster-name: ${{ vars.AKS_CLUSTER_NAME }} resource-group: ${{ vars.AKS_RESOURCE_GROUP }} subscription: ${{ vars.AZURE_SUBSCRIPTION_ID }} @@ -261,12 +283,20 @@ jobs: public-ip: ${{ needs.start-cluster.outputs.cluster-ip }} tls-email: ${{ vars.TLS_EMAIL }} enable-nginx: true - replica-count: '1' + replica-count: "1" secrets: AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} run-tests: - needs: [check-recording-bot-changes, chart-version-checks, start-cluster, build-docker-image, deploy-to-environment, generate-image-tag] + needs: + [ + check-recording-bot-changes, + chart-version-checks, + start-cluster, + build-docker-image, + deploy-to-environment, + generate-image-tag, + ] if: always() && needs.deploy-to-environment.result == 'success' uses: ./.github/workflows/routine-runtests.yml with: @@ -282,4 +312,4 @@ jobs: USER_B_SEED: ${{ secrets.TEST_USER_B_SEED }} USER_C_USERNAME: ${{ vars.TEST_USER_C_USERNAME }} USER_C_PASSWORD: ${{ secrets.TEST_USER_C_PASSWORD }} - USER_C_SEED: ${{ secrets.TEST_USER_C_SEED }} \ No newline at end of file + USER_C_SEED: ${{ secrets.TEST_USER_C_SEED }} diff --git a/.github/workflows/routine-deployenvironment.yml b/.github/workflows/routine-deployenvironment.yml index 8e2c91bdc..10b190d22 100644 --- a/.github/workflows/routine-deployenvironment.yml +++ b/.github/workflows/routine-deployenvironment.yml @@ -4,80 +4,79 @@ on: workflow_call: inputs: environment-name: - description: 'Name of the environment to deploy' + description: "Name of the environment to deploy" required: true type: string - default: 'teams-recording-bot' + default: "teams-recording-bot" port: - description: 'Port number for the service (internal.port)' + description: "Port number for the service (internal.port)" required: true type: string - default: '28550' + default: "28550" cluster-name: - description: 'Name of the AKS cluster' + description: "Name of the AKS cluster" required: false type: string - default: 'aks-sample-cluster' + default: "aks-sample-cluster" resource-group: - description: 'Resource group containing the AKS cluster' + description: "Resource group containing the AKS cluster" required: false type: string - default: 'aks-sample-rg' + default: "aks-sample-rg" subscription: - description: 'Azure subscription ID' + description: "Azure subscription ID" required: false type: string - default: '' + default: "" namespace: - description: 'Kubernetes namespace to deploy to' + description: "Kubernetes namespace to deploy to" required: false type: string - default: 'teams-recording-bot' + default: "teams-recording-bot" host: - description: 'Host domain for the bot (required)' + description: "Host domain for the bot (required)" required: true type: string image-registry: - description: 'Container registry URL' + description: "Container registry URL" required: true type: string image-name: - description: 'Container image name' + description: "Container image name" required: true type: string image-tag: - description: 'Container image tag' - required: false + description: "Container image tag" + required: true type: string - default: 'latest' public-ip: - description: 'Static public IP address for LoadBalancer' + description: "Static public IP address for LoadBalancer" required: true type: string tls-email: - description: 'Email for TLS certificate generation' + description: "Email for TLS certificate generation" required: true type: string enable-nginx: - description: 'Enable nginx ingress controller' + description: "Enable nginx ingress controller" required: false type: boolean default: true replica-count: - description: 'Number of bot replicas to deploy' + description: "Number of bot replicas to deploy" required: false type: string - default: '1' + default: "1" outputs: deployment-status: - description: 'Status of the deployment' + description: "Status of the deployment" value: ${{ jobs.deploy.outputs.deployment-status }} service-url: - description: 'URL of the deployed service' + description: "URL of the deployed service" value: ${{ jobs.deploy.outputs.service-url }} secrets: AZURE_CREDENTIALS: - description: 'Azure credentials for authentication' + description: "Azure credentials for authentication" required: true env: @@ -103,112 +102,144 @@ jobs: service-url: ${{ steps.get-service-url.outputs.url }} steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Azure Login - uses: azure/login@v1 - with: - creds: ${{ secrets.AZURE_CREDENTIALS }} - - - name: Get AKS credentials - run: | - echo "🔑 Getting AKS credentials" - az aks get-credentials --name ${{ env.CLUSTER_NAME }} --resource-group ${{ env.RESOURCE_GROUP }} --subscription ${{ env.AZURE_SUBSCRIPTION_ID }} --overwrite-existing - - - name: Install Helm - uses: azure/setup-helm@v3 - with: - version: 'latest' - - - name: Update Helm dependencies - run: | - echo "📦 Updating Helm dependencies" - helm dependency update - - - name: Create namespace if not exists - run: | - echo "🔧 Ensuring namespace ${{ env.NAMESPACE }} exists" - kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f - - - - name: Prepare Helm values - id: helm-values - run: | - echo "📝 Preparing Helm values for environment: ${{ env.ENVIRONMENT_NAME }}" - - # Create a temporary values file with environment-specific settings - cat > /tmp/environment-values.yaml << EOF - scale: - replicaCount: ${{ inputs.replica-count }} - maxReplicaCount: ${{ inputs.replica-count }} - - host: "${{ inputs.host }}" - - image: - registry: "${{ inputs.image-registry }}" - name: "${{ inputs.image-name }}" - tag: "${{ inputs.image-tag }}" - - ingress: - tls: - email: "${{ inputs.tls-email }}" - - internal: - port: 80 - media: 8445 - - public: - media: ${{ env.PORT}} - ip: "${{ inputs.public-ip }}" - - ingress-nginx: - enabled: ${{ inputs.enable-nginx }} - EOF - - echo "values-file-path=/tmp/environment-values.yaml" >> $GITHUB_OUTPUT - - echo "📄 Generated values file:" - cat /tmp/environment-values.yaml - - - name: Validate Helm chart - run: | - echo "✅ Validating Helm chart" - helm template ${{ env.RELEASE_NAME }} ./ \ - --namespace ${{ env.NAMESPACE }} \ - --values ${{ steps.helm-values.outputs.values-file-path }} \ - --dry-run > /dev/null - echo "✅ Helm chart validation passed" - - - name: Deploy with Helm - run: | - echo "🚀 Deploying ${{ env.ENVIRONMENT_NAME }} Teams Recording Bot to Kubernetes" - helm upgrade --install ${{ env.RELEASE_NAME }} ./ \ - --namespace ${{ env.NAMESPACE }} \ - --values ${{ steps.helm-values.outputs.values-file-path }} \ - --wait \ - --timeout 15m - echo "✅ Deployment completed successfully" - - - name: Verify deployment - run: | - echo "🔍 Verifying deployment" - kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ env.RELEASE_NAME }} - kubectl get services -n ${{ env.NAMESPACE }} - kubectl get ingress -n ${{ env.NAMESPACE }} - - # Wait for StatefulSet to be ready - kubectl wait --for=condition=ready pod -l app=${{ env.RELEASE_NAME }} -n ${{ env.NAMESPACE }} --timeout=1200s - echo "✅ All pods are ready" - - - name: Display deployment summary - run: | - echo "📋 Teams Recording Bot Deployment Summary:" - echo " Environment: ${{ env.ENVIRONMENT_NAME }}" - echo " Namespace: ${{ env.NAMESPACE }}" - echo " Release Name: ${{ env.RELEASE_NAME }}" - echo " Host: ${{ inputs.host }}" - echo " Image: ${{ inputs.image-registry }}/${{ inputs.image-name }}:${{ inputs.image-tag }}" - echo " Replicas: ${{ inputs.replica-count }}" - echo " Internal Port: ${{ env.PORT }}" - echo " Public IP: ${{ inputs.public-ip }}" - echo " Nginx Enabled: ${{ inputs.enable-nginx }}" \ No newline at end of file + - name: Checkout code + uses: actions/checkout@v4 + + - name: Azure Login + uses: azure/login@v1 + with: + creds: ${{ secrets.AZURE_CREDENTIALS }} + + - name: Get AKS credentials + run: | + echo "🔑 Getting AKS credentials" + az aks get-credentials --name ${{ env.CLUSTER_NAME }} --resource-group ${{ env.RESOURCE_GROUP }} --subscription ${{ env.AZURE_SUBSCRIPTION_ID }} --overwrite-existing + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: "3.14.0" + + - name: Update Helm dependencies + run: | + echo "📦 Updating Helm dependencies" + helm dependency update + + - name: Create namespace if not exists + run: | + echo "🔧 Ensuring namespace ${{ env.NAMESPACE }} exists" + kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f - + + - name: Validate inputs + run: | + echo "🔍 Validating deployment inputs" + if [[ -z "${{ inputs.image-tag }}" || "${{ inputs.image-tag }}" == "null" ]]; then + echo "❌ Error: image-tag is required and cannot be empty" + exit 1 + fi + if [[ -z "${{ inputs.image-registry }}" || "${{ inputs.image-registry }}" == "null" ]]; then + echo "❌ Error: image-registry is required and cannot be empty" + exit 1 + fi + if [[ -z "${{ inputs.image-name }}" || "${{ inputs.image-name }}" == "null" ]]; then + echo "❌ Error: image-name is required and cannot be empty" + exit 1 + fi + echo "✅ All required inputs are valid" + echo "Image will be: ${{ inputs.image-registry }}/${{ inputs.image-name }}:${{ inputs.image-tag }}" + + - name: Prepare Helm values + id: helm-values + run: | + echo "📝 Preparing Helm values for environment: ${{ env.ENVIRONMENT_NAME }}" + + # Create a temporary values file with environment-specific settings + cat > /tmp/environment-values.yaml << EOF + scale: + replicaCount: ${{ inputs.replica-count }} + maxReplicaCount: ${{ inputs.replica-count }} + + host: "${{ inputs.host }}" + + image: + registry: "${{ inputs.image-registry }}" + name: "${{ inputs.image-name }}" + tag: "${{ inputs.image-tag }}" + + ingress: + tls: + email: "${{ inputs.tls-email }}" + + internal: + port: 80 + media: 8445 + + public: + media: ${{ env.PORT}} + ip: "${{ inputs.public-ip }}" + + ingress-traefik: + enabled: ${{ inputs.enable-ingress }} + service: + spec: + loadBalancerIP: "${{ inputs.public-ip }}" + EOF + + echo "values-file-path=/tmp/environment-values.yaml" >> $GITHUB_OUTPUT + + echo "📄 Generated values file:" + cat /tmp/environment-values.yaml + + - name: Validate Helm chart + run: | + echo "✅ Validating Helm chart" + helm template ${{ env.RELEASE_NAME }} ./ \ + --namespace ${{ env.NAMESPACE }} \ + --values ${{ steps.helm-values.outputs.values-file-path }} \ + --dry-run > /dev/null + echo "✅ Helm chart validation passed" + + - name: Install Traefik CRDs + run: | + echo "📦 Installing Traefik CRDs from dependency chart" + # Add Traefik Helm repository + helm repo add traefik https://traefik.github.io/charts + helm repo update + # Extract and install CRDs from the Traefik dependency + helm pull traefik/traefik --version 39.0.7 --untar --untardir /tmp + kubectl apply -f /tmp/traefik/crds/ --server-side --force-conflicts 2>/dev/null || true + echo "✅ Traefik CRDs installed" + + - name: Deploy with Helm + run: | + echo "🚀 Deploying ${{ env.ENVIRONMENT_NAME }} Teams Recording Bot to Kubernetes" + helm upgrade --install ${{ env.RELEASE_NAME }} ./ \ + --namespace ${{ env.NAMESPACE }} \ + --values ${{ steps.helm-values.outputs.values-file-path }} \ + --wait \ + --timeout 15m + echo "✅ Deployment completed successfully" + + - name: Verify deployment + run: | + echo "🔍 Verifying deployment" + kubectl get pods -n ${{ env.NAMESPACE }} -l app=${{ env.RELEASE_NAME }} + kubectl get services -n ${{ env.NAMESPACE }} + kubectl get ingress -n ${{ env.NAMESPACE }} + + # Wait for StatefulSet to be ready + kubectl wait --for=condition=ready pod -l app=${{ env.RELEASE_NAME }} -n ${{ env.NAMESPACE }} --timeout=1200s + echo "✅ All pods are ready" + + - name: Display deployment summary + run: | + echo "📋 Teams Recording Bot Deployment Summary:" + echo " Environment: ${{ env.ENVIRONMENT_NAME }}" + echo " Namespace: ${{ env.NAMESPACE }}" + echo " Release Name: ${{ env.RELEASE_NAME }}" + echo " Host: ${{ inputs.host }}" + echo " Image: ${{ inputs.image-registry }}/${{ inputs.image-name }}:${{ inputs.image-tag }}" + echo " Replicas: ${{ inputs.replica-count }}" + echo " Internal Port: ${{ env.PORT }}" + echo " Public IP: ${{ inputs.public-ip }}" + echo " Nginx Enabled: ${{ inputs.enable-nginx }}" diff --git a/deploy/teams-recording-bot/Chart.lock b/deploy/teams-recording-bot/Chart.lock deleted file mode 100644 index 8952b78e3..000000000 --- a/deploy/teams-recording-bot/Chart.lock +++ /dev/null @@ -1,6 +0,0 @@ -dependencies: -- name: ingress-nginx - repository: https://kubernetes.github.io/ingress-nginx - version: 4.8.3 -digest: sha256:7dafa2cf6d937c80fb3cd1791ad242b055f9dc67931e216b6da22350c534177b -generated: "2024-01-08T12:22:54.332827+01:00" diff --git a/deploy/teams-recording-bot/Chart.yaml b/deploy/teams-recording-bot/Chart.yaml index 6616d77e6..c2c46508b 100644 --- a/deploy/teams-recording-bot/Chart.yaml +++ b/deploy/teams-recording-bot/Chart.yaml @@ -16,16 +16,16 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 1.5.2 +version: 2.0.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. -appVersion: 1.4.2 +appVersion: 1.5.0 dependencies: - - name: ingress-nginx - version: 4.8.3 - repository: https://kubernetes.github.io/ingress-nginx - alias: ingress-nginx - condition: ingress-nginx.enabled + - name: traefik + version: 39.0.7 + repository: https://traefik.github.io/charts + alias: ingress-traefik + condition: ingress-traefik.enabled diff --git a/deploy/teams-recording-bot/templates/_helpers.tpl b/deploy/teams-recording-bot/templates/_helpers.tpl index b8989f11a..6c759293e 100644 --- a/deploy/teams-recording-bot/templates/_helpers.tpl +++ b/deploy/teams-recording-bot/templates/_helpers.tpl @@ -3,60 +3,11 @@ {{- default $.Release.Name $.Values.global.override.name -}} {{- end -}} -{{/* Nginx fullName */}} -{{/*We have to differentiate the context this is called in from sub chart or from parent chart*/}} -{{- define "ingress-nginx.fullname" -}} - {{- if $.Values.controller -}} - {{- if $.Values.fullnameOverride -}} - {{- $.Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- default (printf "%s-ingress-nginx" (include "fullName" .)) $.Values.nameOverride -}} - {{- end -}} - {{- else -}} - {{- if (index $.Values "ingress-nginx" "fullnameOverride") -}} - {{- (index $.Values "ingress-nginx" "fullnameOverride") -}} - {{- else -}} - {{- default (printf "%s-ingress-nginx" (include "fullName" .)) (index $.Values "ingress-nginx" "nameOverride") -}} - {{- end -}} - {{- end -}} -{{- end -}} - -{{- define "ingress-nginx.instance" -}} - {{- default $.Release.Name (index $.Values "ingress-nginx" "instance") -}} -{{- end -}} - -{{- define "ingress-nginx.name" -}} - {{- if $.Values.controller -}} - {{- default (include "ingress-nginx.fullname" .) .Values.nameOverride | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- default (include "ingress-nginx.fullname" .) (index $.Values "ingress-nginx" "nameOverride") | trunc 63 | trimSuffix "-" -}} - {{- end -}} -{{- end -}} - -{{/*We have to differentiate the context this is called in from sub chart or from parent chart*/}} -{{- define "ingress-nginx.controller.fullname" -}} - {{- if $.Values.controller -}} - {{- printf "%s-%s" (include "ingress-nginx.fullname" .) $.Values.controller.name | trunc 63 | trimSuffix "-" -}} - {{- else -}} - {{- printf "%s-%s" (include "ingress-nginx.fullname" .) (index $.Values "ingress-nginx" "controller" "name") | trunc 63 | trimSuffix "-" -}} - {{- end -}} -{{- end -}} - {{/* Default namespace */}} {{- define "namespace" -}} {{- default $.Release.Namespace $.Values.global.override.namespace -}} {{- end -}} -{{/* Nginx namespace */}} -{{/*We have to differentiate the context this is called in from sub chart or from parent chart*/}} -{{- define "ingress-nginx.namespace" -}} - {{- if $.Values.controller -}} - {{- default (include "namespace" .) $.Values.namespaceOverride -}} - {{- else -}} - {{- default (include "namespace" .) (index $.Values "ingress-nginx" "namespaceOverride") -}} - {{- end -}} -{{- end -}} - {{/* Check replicaCount is less than maxReplicaCount */}} {{- define "maxCount" -}} {{- if lt (int $.Values.scale.maxReplicaCount) 1 -}} @@ -122,14 +73,3 @@ {{- fail "You need to specify public.ip" -}} {{- end -}} {{- end -}} - -{{/*Update nginx params with generated tcp-config-map*/}} -{{/*because it is called in the context of the subchart we can only use global values or the subcharts values*/}} -{{- define "ingress-nginx.params" -}} -- /nginx-ingress-controller -- --election-id={{ include "ingress-nginx.controller.electionID" . }} -- --controller-class=k8s.io/{{ include "ingress-nginx.fullname" .}} -- --ingress-class={{ include "ingress-nginx.fullname" .}} -- --configmap=$(POD_NAMESPACE)/{{ include "ingress-nginx.controller.fullname" . }} -- --tcp-services-configmap={{ include "ingress-nginx.namespace" . }}/{{ include "fullName" . }}-tcp-services -{{- end -}} \ No newline at end of file diff --git a/deploy/teams-recording-bot/templates/cluster-issuer.yaml b/deploy/teams-recording-bot/templates/cluster-issuer.yaml index 5af521fb6..6731471d7 100644 --- a/deploy/teams-recording-bot/templates/cluster-issuer.yaml +++ b/deploy/teams-recording-bot/templates/cluster-issuer.yaml @@ -19,4 +19,4 @@ spec: solvers: - http01: ingress: - ingressClassName: {{ include "ingress-nginx.fullname" . }} + ingressClassName: {{ .Values.ingress.className }} diff --git a/deploy/teams-recording-bot/templates/configmap.yaml b/deploy/teams-recording-bot/templates/configmap.yaml deleted file mode 100644 index 710bfcf9f..000000000 --- a/deploy/teams-recording-bot/templates/configmap.yaml +++ /dev/null @@ -1,17 +0,0 @@ -{{- $fullName := include "fullName" . -}} -{{- $namespace := include "namespace" . -}} -{{- $nginxNamespace := include "ingress-nginx.namespace" . -}} -{{- $maxCount := include "maxCount" . -}} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ $fullName }}-tcp-services - namespace: {{ $nginxNamespace }} - labels: - helmVersion: {{ .Chart.Version }} - helmAppVersion: {{ .Chart.AppVersion }} - helmName: {{ .Chart.Name }} -data: -{{- range $i, $e := until (int $maxCount) }} - {{ (int $.Values.public.media) | add $i | quote | nindent 2 }}: {{ $namespace }}/{{ $fullName }}-{{ $i }}:{{ $.Values.internal.media }} -{{- end }} diff --git a/deploy/teams-recording-bot/templates/deployment.yaml b/deploy/teams-recording-bot/templates/deployment.yaml index 8af298934..aa705c167 100644 --- a/deploy/teams-recording-bot/templates/deployment.yaml +++ b/deploy/teams-recording-bot/templates/deployment.yaml @@ -52,17 +52,18 @@ spec: terminationGracePeriodSeconds: {{ .Values.terminationGracePeriod }} containers: - name: recording-bot - image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + image: "{{ .Values.image.registry }}/{{ .Values.image.name }}:{{ required "image.tag must be specified" .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} - lifecycle: - preStop: - exec: - command: - - powershell - - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine; - - .\halt_termination.ps1 *>> halt_termination.log + # lifecycle: + # preStop: + # exec: + # command: + # - powershell + # - Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine; + # - .\halt_termination.ps1 *>> halt_termination.log ports: - containerPort: {{ .Values.internal.port }} + - containerPort: 81 - containerPort: {{ .Values.internal.media }} volumeMounts: - mountPath: "C:/certs/" diff --git a/deploy/teams-recording-bot/templates/external.yaml b/deploy/teams-recording-bot/templates/external.yaml index 60d4f7318..3eb5293a8 100644 --- a/deploy/teams-recording-bot/templates/external.yaml +++ b/deploy/teams-recording-bot/templates/external.yaml @@ -1,37 +1,23 @@ {{- $maxCount := include "maxCount" . -}} -{{- $namespace := include "ingress-nginx.namespace" . -}} -{{- $fullName := include "ingress-nginx.fullname" . -}} +{{- $fullName := include "fullName" . -}} +{{- $namespace := include "namespace" . -}} +{{- $publicIp := include "publicIP" . -}} +{{- range $i, $e := until (int $maxCount) }} apiVersion: v1 kind: Service metadata: name: {{ $fullName }}-external namespace: {{ $namespace }} - labels: - helmVersion: {{ .Chart.Version }} - helmAppVersion: {{ .Chart.AppVersion }} - helmName: {{ .Chart.Name }} spec: type: LoadBalancer externalTrafficPolicy: Cluster - loadBalancerIP: {{ include "publicIP" . }} + loadBalancerIP: {{ $publicIp }} ports: -{{- if (index $.Values "ingress-nginx" "enabled") }} - - name: http - port: {{ $.Values.public.http }} - targetPort: http - protocol: TCP - - name: https - port: {{ $.Values.public.https }} - targetPort: https - protocol: TCP -{{- end }} -{{- range $i, $e := until (int $maxCount) }} - name: {{ $.Values.public.media | add $i }}-tcp port: {{ $.Values.public.media | add $i }} - targetPort: {{ $.Values.public.media | add $i }} + targetPort: {{ $.Values.internal.media }} protocol: TCP -{{- end }} selector: - app.kubernetes.io/component: controller - app.kubernetes.io/instance: {{ include "ingress-nginx.instance" . }} - app.kubernetes.io/name: {{ include "ingress-nginx.name" .}} \ No newline at end of file + app: {{ $fullName }} + statefulset.ubernetes.io/pod-name: {{ $fullName }}-{{ $i }} +{{- end }} \ No newline at end of file diff --git a/deploy/teams-recording-bot/templates/ingress.yaml b/deploy/teams-recording-bot/templates/ingress.yaml index 30cfd12fb..2a3abb753 100644 --- a/deploy/teams-recording-bot/templates/ingress.yaml +++ b/deploy/teams-recording-bot/templates/ingress.yaml @@ -1,5 +1,6 @@ {{- $fullName := include "fullName" . -}} {{- $namespace := include "namespace" . -}} +{{- $maxCount := include "maxCount" . -}} apiVersion: networking.k8s.io/v1 kind: Ingress metadata: @@ -11,13 +12,8 @@ metadata: helmName: {{ .Chart.Name }} annotations: cert-manager.io/cluster-issuer: {{ $fullName }}-issuer - nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" - nginx.ingress.kubernetes.io/server-snippet: | - location ~* ^({{ include "ingress.path.withTrailingSlash" . }})(?[0-9]*)/api/calling/notification { - proxy_pass https://{{ $fullName }}-$instance.{{ $fullName }}.{{ $namespace }}.svc.cluster.local:{{ .Values.internal.port }}; - } spec: - ingressClassName: {{ include "ingress-nginx.fullname" .}} + ingressClassName: {{ .Values.ingress.className }} tls: - hosts: - {{ include "hostName" . }} @@ -26,10 +22,19 @@ spec: - host: {{ include "hostName" . }} http: paths: - - path: {{ include "ingress.path" . }} - pathType: Prefix - backend: - service: - name: {{ $fullName }}-routing - port: - number: 443 \ No newline at end of file + {{- range $i, $e := until (int $maxCount) }} + - path: /{{ $i }} + pathType: Prefix + backend: + service: + name: {{ $fullName }}-{{ $i }} + port: + number: 80 + {{- end }} + - path: {{ include "ingress.path" . }} + pathType: Prefix + backend: + service: + name: {{ $fullName }}-routing + port: + number: 80 \ No newline at end of file diff --git a/deploy/teams-recording-bot/templates/ingressclass.yaml b/deploy/teams-recording-bot/templates/ingressclass.yaml deleted file mode 100644 index 1e1d35621..000000000 --- a/deploy/teams-recording-bot/templates/ingressclass.yaml +++ /dev/null @@ -1,16 +0,0 @@ -{{- $fullName := include "ingress-nginx.fullname" . -}} -{{- if (index $.Values "ingress-nginx" "enabled") -}} -apiVersion: networking.k8s.io/v1 -kind: IngressClass -metadata: - labels: - helmVersion: {{ .Chart.Version }} - helmAppVersion: {{ .Chart.AppVersion }} - helmName: {{ .Chart.Name }} - app.kubernetes.io/name: {{ include "ingress-nginx.name" . }} - app.kubernetes.io/instance: {{ .Release.Name }} - app.kubernetes.io/component: controller - name: {{ $fullName }} -spec: - controller: "k8s.io/{{$fullName}}" -{{- end -}} \ No newline at end of file diff --git a/deploy/teams-recording-bot/templates/routing.yaml b/deploy/teams-recording-bot/templates/routing.yaml index ed8904d7c..df456fa78 100644 --- a/deploy/teams-recording-bot/templates/routing.yaml +++ b/deploy/teams-recording-bot/templates/routing.yaml @@ -13,7 +13,7 @@ spec: clusterIP: None ports: - name: public - port: 443 - targetPort: {{ $.Values.internal.port }} + port: 80 + targetPort: 81 selector: app: {{ $fullName }} diff --git a/deploy/teams-recording-bot/templates/headless.yaml b/deploy/teams-recording-bot/templates/servers-transport.yaml similarity index 53% rename from deploy/teams-recording-bot/templates/headless.yaml rename to deploy/teams-recording-bot/templates/servers-transport.yaml index 1c5bd0a55..08bf6c977 100644 --- a/deploy/teams-recording-bot/templates/headless.yaml +++ b/deploy/teams-recording-bot/templates/servers-transport.yaml @@ -1,20 +1,14 @@ {{- $fullName := include "fullName" . -}} {{- $namespace := include "namespace" . -}} -apiVersion: v1 -kind: Service +apiVersion: traefik.io/v1alpha1 +kind: ServersTransportTCP metadata: - name: {{ $fullName }} + name: {{ $fullName }}-transport namespace: {{ $namespace }} labels: helmVersion: {{ .Chart.Version }} helmAppVersion: {{ .Chart.AppVersion }} helmName: {{ .Chart.Name }} spec: - clusterIP: None - publishNotReadyAddresses: true - ports: - - name: public - port: 443 - targetPort: {{ .Values.internal.port }} - selector: - app: {{ $fullName }} + tls: + insecureSkipVerify: true \ No newline at end of file diff --git a/deploy/teams-recording-bot/templates/service.yaml b/deploy/teams-recording-bot/templates/service.yaml index 84b9687a8..058b787fa 100644 --- a/deploy/teams-recording-bot/templates/service.yaml +++ b/deploy/teams-recording-bot/templates/service.yaml @@ -11,6 +11,8 @@ metadata: helmVersion: {{ $.Chart.Version }} helmAppVersion: {{ $.Chart.AppVersion }} helmName: {{ $.Chart.Name }} + annotations: + traefik.ingress.kubernetes.io/service.nativelb: "true" spec: type: ClusterIP publishNotReadyAddresses: true @@ -18,6 +20,9 @@ spec: - name: media port: {{ $.Values.internal.media }} targetPort: {{ $.Values.internal.media }} + - name: signaling + port: 80 + targetPort: 81 selector: statefulset.kubernetes.io/pod-name: {{ $fullName }}-{{ $i }} --- diff --git a/deploy/teams-recording-bot/values.yaml b/deploy/teams-recording-bot/values.yaml index 0383d6d7a..88373d868 100644 --- a/deploy/teams-recording-bot/values.yaml +++ b/deploy/teams-recording-bot/values.yaml @@ -1,6 +1,6 @@ global: override: - name: "" + name: "" namespace: "" scale: @@ -10,12 +10,13 @@ scale: host: null image: - registry: null - name: null - tag: null + registry: null # Must be provided at deployment time (e.g., ghcr.io) + name: null # Must be provided at deployment time (e.g., org/repo-name) + tag: null # Must be provided at deployment time (e.g., CI-generated hash) pullPolicy: IfNotPresent ingress: + className: traefik path: / tls: email: YOUR_EMAIL @@ -68,16 +69,37 @@ resources: {} # cpu: 100m # memory: 128Mi -ingress-nginx: +ingress-traefik: enabled: true - controller: - ingressClassRessource: - enabled: false - allowSnippetAnnotations: true - replicaCount: 1 - nodeSelector: - "kubernetes.io/os": linux - service: - enabled: false - admissionWebhooks: - enabled: false \ No newline at end of file + nodeSelector: + "kubernetes.io/os": linux + ingressClass: + enabled: true + isDefaultClass: true + name: traefik + service: + spec: + loadBalancerIP: "OVERRIDE THIS DURING DEPLOYMENT TO USE CLUSTER PUBLIC IP" + deployment: + replicas: 3 + podDisruptionBudget: + enabled: true + minAvailable: 1 + resources: + requests: + cpu: "100m" + memory: "50Mi" + limits: + cpu: "300m" + memory: "150Mi" + autoscaling: + enabled: true + minReplicas: 2 + maxReplicas: 5 + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 70 diff --git a/src/RecordingBot.Services/ServiceSetup/AppHost.cs b/src/RecordingBot.Services/ServiceSetup/AppHost.cs index 6ec464988..7e501bbb3 100644 --- a/src/RecordingBot.Services/ServiceSetup/AppHost.cs +++ b/src/RecordingBot.Services/ServiceSetup/AppHost.cs @@ -80,7 +80,7 @@ public void Boot(string[] args) app.UsePathBase(azureSettings.PodPathBase); app.UsePathBase(azureSettings.ServicePath); - app.UseHttpsRedirection(); + //app.UseHttpsRedirection(); app.UseAuthorization();