From 42f21d48d2b585ce82c225089bca2c0d12b876ba Mon Sep 17 00:00:00 2001 From: Andrea Petrucci Date: Thu, 21 Dec 2023 11:52:39 +0100 Subject: [PATCH] new workflow --- .env | 2 +- .../action.yml | 55 ----- .../action.yml | 62 ----- .github/actions/lint-python-app/action.yml | 28 --- .github/actions/test-python-app/action.yml | 41 ---- .github/workflows/face-detection.yml | 148 ----------- .github/workflows/workflow.yml | 232 ++++++++++++++++++ kubernetes/config-map.yml | 14 ++ kubernetes/face-detection.config-map.yml | 11 - kubernetes/face-detection.ingress.yml | 22 -- kubernetes/face-detection.stateful.yml | 36 --- kubernetes/ingress.yml | 22 ++ ...face-detection.service.yml => service.yml} | 6 +- kubernetes/stateful.yml | 28 +++ 14 files changed, 300 insertions(+), 407 deletions(-) delete mode 100644 .github/actions/build-and-push-docker-image-to-github/action.yml delete mode 100644 .github/actions/execute-command-on-kubernetes-cluster/action.yml delete mode 100644 .github/actions/lint-python-app/action.yml delete mode 100644 .github/actions/test-python-app/action.yml delete mode 100644 .github/workflows/face-detection.yml create mode 100644 .github/workflows/workflow.yml create mode 100644 kubernetes/config-map.yml delete mode 100644 kubernetes/face-detection.config-map.yml delete mode 100644 kubernetes/face-detection.ingress.yml delete mode 100644 kubernetes/face-detection.stateful.yml create mode 100644 kubernetes/ingress.yml rename kubernetes/{face-detection.service.yml => service.yml} (66%) create mode 100644 kubernetes/stateful.yml diff --git a/.env b/.env index 7848b95..f503607 100644 --- a/.env +++ b/.env @@ -8,7 +8,7 @@ ENVIRONMENT=development ENGINE_URLS=["http://localhost:8080"] # The Service URL -SERVICE_URL="http://localhost:8686" +SERVICE_URL="http://localhost:9090" # The maximum of tasks the service can process MAX_TASKS=50 diff --git a/.github/actions/build-and-push-docker-image-to-github/action.yml b/.github/actions/build-and-push-docker-image-to-github/action.yml deleted file mode 100644 index 8afff00..0000000 --- a/.github/actions/build-and-push-docker-image-to-github/action.yml +++ /dev/null @@ -1,55 +0,0 @@ -# Documentation: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action -name: build_and_push_docker_image_to_github -description: Build and push Docker image to GitHub - -inputs: - docker-registry-url: - description: Docker registry URL - required: true - default: ghcr.io - docker-registry-username: - description: Docker registry username - required: true - docker-registry-password: - description: Docker registry password - required: true - docker-image-name: - description: Docker image name - required: true - docker-image-context: - description: Docker image context - required: true - default: . - -outputs: - docker-image-tags: - description: "Docker image tags" - value: ${{ steps.meta.outputs.tags }} - -runs: - using: composite - steps: - - name: Log in to the Container registry - uses: docker/login-action@v2 - with: - registry: ${{ inputs.docker-registry-url }} - username: ${{ inputs.docker-registry-username }} - password: ${{ inputs.docker-registry-password }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v2 - with: - images: | - ${{ inputs.docker-registry-url }}/${{ inputs.docker-image-name }} - tags: | - type=raw,value=latest - type=sha - - - name: Build and push Docker image - uses: docker/build-push-action@v2 - with: - context: ${{ inputs.docker-image-context }} - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/actions/execute-command-on-kubernetes-cluster/action.yml b/.github/actions/execute-command-on-kubernetes-cluster/action.yml deleted file mode 100644 index a742295..0000000 --- a/.github/actions/execute-command-on-kubernetes-cluster/action.yml +++ /dev/null @@ -1,62 +0,0 @@ -# Documentation: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action -name: execute_command_on_kubernetes_cluster -description: Execute a command on a Kubernetes cluster - -inputs: - kubectl-binary-url: - description: kubectl binary URL - required: true - default: https://dl.k8s.io/release/v1.25.3/bin/linux/amd64/kubectl - kubectl-binary-sha-url: - description: kubectl binary SHA URL - required: true - default: https://dl.k8s.io/v1.25.3/bin/linux/amd64/kubectl.sha256 - kube-config: - description: kubectl config file - required: true - kube-namespace: - description: kubectl namespace - required: true - kubectl-context: - description: kubectl context - required: true - default: . - kubectl-args: - description: kubectl arguments - required: true - -runs: - using: composite - steps: - - name: Get filenames from URLs - shell: bash - run: | - echo "KUBECTL_BINARY_NAME=$(basename "${{ inputs.kubectl-binary-url }}")" >> $GITHUB_ENV - echo "KUBECTL_BINARY_SHA_NAME=$(basename "${{ inputs.kubectl-binary-sha-url }}")" >> $GITHUB_ENV - - - name: Download kubectl binary - shell: bash - run: curl -LO -s "${{ inputs.kubectl-binary-url }}" - - - name: Download kubectl binary SHA - shell: bash - run: curl -LO -s "${{ inputs.kubectl-binary-sha-url }}" - - - name: Verify kubectl binary with SHA checksum - shell: bash - run: echo "$(cat $KUBECTL_BINARY_SHA_NAME) kubectl" | sha256sum --check - - - name: Install kubectl binary - shell: bash - run: sudo install -o root -g root -m 0755 $KUBECTL_BINARY_NAME /usr/local/bin/kubectl - - - name: Create kubectl config file - shell: bash - run: | - mkdir --parent ~/.kube - echo "${{ inputs.kube-config }}" > ~/.kube/config - - - name: Execute kubectl command - shell: bash - working-directory: ${{ inputs.kubectl-context }} - run: kubectl --namespace "${{ inputs.kube-namespace }}" ${{ inputs.kubectl-args }} diff --git a/.github/actions/lint-python-app/action.yml b/.github/actions/lint-python-app/action.yml deleted file mode 100644 index a246d92..0000000 --- a/.github/actions/lint-python-app/action.yml +++ /dev/null @@ -1,28 +0,0 @@ -# Documentation: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action -name: lint_python_app -description: Lint a Python app - -inputs: - python-app-path: - description: Python app path - required: true - default: . - -runs: - using: composite - steps: - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' - - - name: Install app dependencies - shell: bash - working-directory: ${{ inputs.python-app-path }} - run: pip3 install flake8 - - - name: Lint Python code - shell: bash - working-directory: ${{ inputs.python-app-path }} - run: flake8 . diff --git a/.github/actions/test-python-app/action.yml b/.github/actions/test-python-app/action.yml deleted file mode 100644 index 134e6f4..0000000 --- a/.github/actions/test-python-app/action.yml +++ /dev/null @@ -1,41 +0,0 @@ -# Documentation: https://docs.github.com/en/actions/creating-actions/creating-a-composite-action -name: test_python_app -description: Test a Python app - -inputs: - python-app-path: - description: Python app path - required: true - default: . - token: - description: GitHub token - required: true - default: "" - -runs: - using: composite - steps: - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: '3.10' - cache: 'pip' - - - name: Install app dependencies - shell: bash - working-directory: ${{ inputs.python-app-path }} - run: pip3 install -r requirements.txt -r requirements-all.txt - - - name: Run Python tests - shell: bash - working-directory: ${{ inputs.python-app-path }} - run: pytest - - - name: Coverage report - uses: orgoro/coverage@v3.1 - if: github.event_name == 'pull_request' - with: - coverageFile: ${{ inputs.python-app-path }}/coverage.xml - token: ${{ inputs.token }} - - diff --git a/.github/workflows/face-detection.yml b/.github/workflows/face-detection.yml deleted file mode 100644 index ac488ba..0000000 --- a/.github/workflows/face-detection.yml +++ /dev/null @@ -1,148 +0,0 @@ -# Documentation: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses -name: face-detection_workflow -run-name: face-detection workflow - -# Allow one concurrent deployment -concurrency: - group: "face-detection" - cancel-in-progress: true - -on: - push: - branches: - - main - - prod - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -jobs: - review: - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - - - name: Lint Python app - uses: ./.github/actions/lint-python-app - with: - python-app-path: . - - test: - needs: review - runs-on: ubuntu-latest - steps: - - name: Clone repository - uses: actions/checkout@v3 - - - name: Test Python app - uses: ./.github/actions/test-python-app - with: - python-app-path: . - token: ${{ secrets.GITHUB_TOKEN }} - - release: - needs: test - runs-on: ubuntu-latest - # Only run on main - if: success() && github.ref == 'refs/heads/main' - steps: - - name: Clone repository - uses: actions/checkout@v3 - - - name: Build and push Docker image to GitHub - id: build-and-push-docker-image-to-github - uses: ./.github/actions/build-and-push-docker-image-to-github - with: - docker-registry-username: ${{ github.actor }} - docker-registry-password: ${{ secrets.GITHUB_TOKEN }} - docker-image-name: swiss-ai-center/face-detection - docker-image-context: . - outputs: - docker-image-tags: ${{ steps.build-and-push-docker-image-to-github.outputs.docker-image-tags }} - - deploy-dev: - needs: release - runs-on: ubuntu-latest - # Only run on main - if: success() && github.ref == 'refs/heads/main' - steps: - - name: Clone repository - uses: actions/checkout@v3 - - - name: Prepare configuration files - shell: bash - working-directory: ./kubernetes - env: - ENVIRONMENT: production - LOG_LEVEL: info - ENGINE_URLS: "'[\"https://backend-core-engine-swiss-ai-center.kube.isc.heia-fr.ch\"]'" - SERVICE_URL: https://face-detection-swiss-ai-center.kube.isc.heia-fr.ch - run: | - # Set face-detection version - docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) - docker_image_sha_tag="${docker_image_tags[1]}" - yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" face-detection.stateful.yml > new-face-detection.stateful.yml && mv new-face-detection.stateful.yml face-detection.stateful.yml - - # Set face-detection configuration (ConfigMap) - yq '.data = (.data | to_entries | map({"key": .key, "value": "${" + .key + "}"}) | from_entries)' face-detection.config-map.yml | envsubst > new-face-detection.config-map.yml && mv new-face-detection.config-map.yml face-detection.config-map.yml - - # Set face-detection configuration (Ingress) - yq ".spec.rules[0].host = \"${SERVICE_URL#*://}\"" face-detection.ingress.yml > new-face-detection.ingress.yml && mv new-face-detection.ingress.yml face-detection.ingress.yml - yq ".spec.tls[0].hosts[0] = \"${SERVICE_URL#*://}\"" face-detection.ingress.yml > new-face-detection.ingress.yml && mv new-face-detection.ingress.yml face-detection.ingress.yml - - - name: Deploy face-detection on the Kubernetes cluster - uses: ./.github/actions/execute-command-on-kubernetes-cluster - with: - kube-config: ${{ secrets.KUBE_CONFIG_DEV }} - kube-namespace: swiss-ai-center-dev - kubectl-context: ./kubernetes - kubectl-args: | - apply \ - -f face-detection.config-map.yml \ - -f face-detection.stateful.yml \ - -f face-detection.service.yml \ - -f face-detection.ingress.yml - - deploy-prod: - needs: release - runs-on: ubuntu-latest - # Only run on prod - if: success() && github.ref == 'refs/heads/prod' - steps: - - name: Clone repository - uses: actions/checkout@v3 - - - name: Prepare configuration files - shell: bash - working-directory: ./kubernetes - env: - ENVIRONMENT: production - LOG_LEVEL: info - ENGINE_URLS: "'[\"https://backend-core-engine-swiss-ai-center.kube.isc.heia-fr.ch\"]'" - SERVICE_URL: https://face-detection-swiss-ai-center.kube.isc.heia-fr.ch - run: | - # Set face-detection version - docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) - docker_image_sha_tag="${docker_image_tags[1]}" - yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" face-detection.stateful.yml > new-face-detection.stateful.yml && mv new-face-detection.stateful.yml face-detection.stateful.yml - - # Set face-detection configuration (ConfigMap) - yq '.data = (.data | to_entries | map({"key": .key, "value": "${" + .key + "}"}) | from_entries)' face-detection.config-map.yml | envsubst > new-face-detection.config-map.yml && mv new-face-detection.config-map.yml face-detection.config-map.yml - - # Set face-detection configuration (Ingress) - yq ".spec.rules[0].host = \"${SERVICE_URL#*://}\"" face-detection.ingress.yml > new-face-detection.ingress.yml && mv new-face-detection.ingress.yml face-detection.ingress.yml - yq ".spec.tls[0].hosts[0] = \"${SERVICE_URL#*://}\"" face-detection.ingress.yml > new-face-detection.ingress.yml && mv new-face-detection.ingress.yml face-detection.ingress.yml - - - name: Deploy face-detection on the Kubernetes cluster - uses: ./.github/actions/execute-command-on-kubernetes-cluster - with: - kube-config: ${{ secrets.KUBE_CONFIG_PROD }} - kube-namespace: swiss-ai-center-prod - kubectl-context: ./kubernetes - kubectl-args: | - apply \ - -f face-detection.config-map.yml \ - -f face-detection.stateful.yml \ - -f face-detection.service.yml \ - -f face-detection.ingress.yml diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml new file mode 100644 index 0000000..dac9fe4 --- /dev/null +++ b/.github/workflows/workflow.yml @@ -0,0 +1,232 @@ +# Documentation: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsuses +name: github_worflow +run-name: GitHub Workflow + +env: + ## Common environment variables + # Service name (must be lowercase and not contain any spaces) + SERVICE_NAME: ${{ vars.SERVICE_NAME }} + + ## Development environment variables + # The URLs of the Core Engine to which the service should connect + DEV_CORE_ENGINE_URLS: ${{ vars.DEV_CORE_ENGINE_URLS }} + # The URL that the service (dev) should be accessible at + DEV_SERVICE_URL: ${{ vars.DEV_SERVICE_URL }} + # The Kubernetes namespace that the service should be deployed to + DEV_NAMESPACE: ${{ vars.DEV_NAMESPACE }} + # Maximum number of tasks the service can accept + DEV_MAX_TASKS: ${{ vars.DEV_MAX_TASKS }} + # Number of retries on the Engine for announcement + DEV_ENGINE_ANNOUNCE_RETRIES: ${{ vars.DEV_ENGINE_ANNOUNCE_RETRIES }} + # Delay between each retry + DEV_ENGINE_ANNOUNCE_RETRY_DELAY: ${{ vars.DEV_ENGINE_ANNOUNCE_RETRY_DELAY }} + # Logging level + DEV_LOG_LEVEL: ${{ vars.DEV_LOG_LEVEL }} + # Kube configuration + DEV_KUBE_CONFIG: ${{ secrets.DEV_KUBE_CONFIG }} + + ## Production environment variables + # The URLs of the Core Engine to which the service should connect + PROD_CORE_ENGINE_URLS: ${{ vars.PROD_CORE_ENGINE_URLS }} + # The URL that the service (dev) should be accessible at + PROD_SERVICE_URL: ${{ vars.PROD_SERVICE_URL }} + # The Kubernetes namespace that the service should be deployed to + PROD_NAMESPACE: ${{ vars.PROD_NAMESPACE }} + # Maximum number of tasks the service can accept + PROD_MAX_TASKS: ${{ vars.PROD_MAX_TASKS }} + # Number of retries on the Engine for announcement + PROD_ENGINE_ANNOUNCE_RETRIES: ${{ vars.PROD_ENGINE_ANNOUNCE_RETRIES }} + # Delay between each retry + PROD_ENGINE_ANNOUNCE_RETRY_DELAY: ${{ vars.PROD_ENGINE_ANNOUNCE_RETRY_DELAY }} + # Logging level + PROD_LOG_LEVEL: ${{ vars.PROD_LOG_LEVEL }} + # Kube configuration + PROD_KUBE_CONFIG: ${{ secrets.DEV_KUBE_CONFIG }} + +# Allow one concurrent deployment +concurrency: + group: github_worflow + cancel-in-progress: true + +on: + push: + branches: + - main + - prod + + pull_request: + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +jobs: + review: + runs-on: ubuntu-latest + if: ${{ vars.RUN_CICD == 'true' }} + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Lint Python app + uses: swiss-ai-center/common-code/.github/actions/lint-python-app@main + with: + python-app-path: . + + test: + needs: review + runs-on: ubuntu-latest + if: ${{ vars.RUN_CICD == 'true' }} + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Test Python app + uses: swiss-ai-center/common-code/.github/actions/test-python-app@main + with: + python-app-path: . + token: ${{ secrets.GITHUB_TOKEN }} + + release: + needs: test + runs-on: ubuntu-latest + if: ${{ vars.RUN_CICD == 'true' && success() && (vars.DEPLOY_DEV == 'true' || vars.DEPLOY_PROD == 'true') }} + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Build and push Docker image to GitHub + id: build-and-push-docker-image-to-github + uses: swiss-ai-center/common-code/.github/actions/build-and-push-docker-image-to-github@main + with: + docker-registry-username: ${{ github.actor }} + docker-registry-password: ${{ secrets.GITHUB_TOKEN }} + docker-image-name: ${{ github.repository }} + docker-image-context: . + outputs: + docker-image-tags: ${{ steps.build-and-push-docker-image-to-github.outputs.docker-image-tags }} + + deploy-dev: + needs: release + runs-on: ubuntu-latest + if: ${{ vars.RUN_CICD == 'true' && success() && github.ref == 'refs/heads/main' && vars.DEPLOY_DEV == 'true' }} + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Prepare configuration files + shell: bash + working-directory: ./kubernetes + env: + ENVIRONMENT: development + LOG_LEVEL: ${{ env.DEV_LOG_LEVEL }} + ENGINE_URLS: ${{ env.DEV_CORE_ENGINE_URLS }} + SERVICE_URL: ${{ env.DEV_SERVICE_URL }} + MAX_TASKS: ${{ env.DEV_MAX_TASKS }} + ENGINE_ANNOUNCE_RETRIES: ${{ env.DEV_ENGINE_ANNOUNCE_RETRIES }} + ENGINE_ANNOUNCE_RETRY_DELAY: ${{ env.DEV_ENGINE_ANNOUNCE_RETRY_DELAY }} + run: | + # Set service version + docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) + docker_image_sha_tag="${docker_image_tags[1]}" + yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + + # Set service configuration (ConfigMap) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-config\"" config-map.yml > new-config-map.yml && mv new-config-map.yml config-map.yml + yq ".metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" config-map.yml > new-config-map.yml && mv new-config-map.yml config-map.yml + yq '.data = (.data | to_entries | map({"key": .key, "value": "${" + .key + "}"}) | from_entries)' config-map.yml | envsubst > new-config-map.yml && mv new-config-map.yml config-map.yml + + # Set service configuration (Ingress) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-ingress\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.rules[0].host = \"${SERVICE_URL#*://}\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.rules[0].http.paths[0].backend.service.name = \"${{ env.SERVICE_NAME }}-service\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.tls[0].hosts[0] = \"${SERVICE_URL#*://}\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + + # Set service configuration (Service) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-service\"" service.yml > new-service.yml && mv new-service.yml service.yml + yq ".spec.selector.app = \"${{ env.SERVICE_NAME }}\"" service.yml > new-service.yml && mv new-service.yml service.yml + + # Set service configuration (StatefulSet) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-stateful\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.serviceName = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.selector.matchLabels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].name = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].envFrom[0].configMapRef.name = \"${{ env.SERVICE_NAME }}-config\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + + - name: Deploy ${{ env.SERVICE_NAME }} on the Kubernetes cluster + uses: swiss-ai-center/common-code/.github/actions/execute-command-on-kubernetes-cluster@main + with: + kube-config: ${{ env.DEV_KUBE_CONFIG }} + kube-namespace: ${{ env.DEV_NAMESPACE }} + kubectl-context: ./kubernetes + kubectl-args: | + apply \ + -f config-map.yml \ + -f stateful.yml \ + -f service.yml \ + -f ingress.yml + + deploy-prod: + needs: release + runs-on: ubuntu-latest + if: ${{ vars.RUN_CICD == 'true' && success() && github.ref == 'refs/heads/prod' && vars.DEPLOY_PROD == 'true' }} + steps: + - name: Clone repository + uses: actions/checkout@v3 + + - name: Prepare configuration files + shell: bash + working-directory: ./kubernetes + env: + ENVIRONMENT: development + LOG_LEVEL: ${{ env.PROD_LOG_LEVEL }} + ENGINE_URLS: ${{ env.PROD_CORE_ENGINE_URLS }} + SERVICE_URL: ${{ env.PROD_SERVICE_URL }} + MAX_TASKS: ${{ env.PROD_MAX_TASKS }} + ENGINE_ANNOUNCE_RETRIES: ${{ env.PROD_ENGINE_ANNOUNCE_RETRIES }} + ENGINE_ANNOUNCE_RETRY_DELAY: ${{ env.PROD_ENGINE_ANNOUNCE_RETRY_DELAY }} + run: | + # Set service version + docker_image_tags=(${{ needs.release.outputs.docker-image-tags }}) + docker_image_sha_tag="${docker_image_tags[1]}" + yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + + # Set service configuration (ConfigMap) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-config\"" config-map.yml > new-config-map.yml && mv new-config-map.yml config-map.yml + yq ".metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" config-map.yml > new-config-map.yml && mv new-config-map.yml config-map.yml + yq '.data = (.data | to_entries | map({"key": .key, "value": "${" + .key + "}"}) | from_entries)' config-map.yml | envsubst > new-config-map.yml && mv new-config-map.yml config-map.yml + + # Set service configuration (Ingress) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-ingress\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.rules[0].host = \"${SERVICE_URL#*://}\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.rules[0].http.paths[0].backend.service.name = \"${{ env.SERVICE_NAME }}-service\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + yq ".spec.tls[0].hosts[0] = \"${SERVICE_URL#*://}\"" ingress.yml > new-ingress.yml && mv new-ingress.yml ingress.yml + + # Set service configuration (Service) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-service\"" service.yml > new-service.yml && mv new-service.yml service.yml + yq ".spec.selector.app = \"${{ env.SERVICE_NAME }}\"" service.yml > new-service.yml && mv new-service.yml service.yml + + # Set service configuration (StatefulSet) + yq ".metadata.name = \"${{ env.SERVICE_NAME }}-stateful\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.serviceName = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.selector.matchLabels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.metadata.labels.app = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].name = \"${{ env.SERVICE_NAME }}\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].image = \"$docker_image_sha_tag\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + yq ".spec.template.spec.containers[0].envFrom[0].configMapRef.name = \"${{ env.SERVICE_NAME }}-config\"" stateful.yml > new-stateful.yml && mv new-stateful.yml stateful.yml + + - name: Deploy ${{ env.SERVICE_NAME }} on the Kubernetes cluster + uses: swiss-ai-center/common-code/.github/actions/execute-command-on-kubernetes-cluster@main + with: + kube-config: ${{ secrets.PROD_KUBE_CONFIG }} + kube-namespace: ${{ env.PROD_NAMESPACE }} + kubectl-context: ./kubernetes + kubectl-args: | + apply \ + -f config-map.yml \ + -f stateful.yml \ + -f service.yml \ + -f ingress.yml diff --git a/kubernetes/config-map.yml b/kubernetes/config-map.yml new file mode 100644 index 0000000..6609cb6 --- /dev/null +++ b/kubernetes/config-map.yml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: my-service-config + labels: + app: my-service +data: + ENVIRONMENT: development + LOG_LEVEL: debug + ENGINE_URLS: '["http://core-engine-service:8080"]' + SERVICE_URL: http://my-service-service:9090 + MAX_TASKS: '50' + ENGINE_ANNOUNCE_RETRIES: '5' + ENGINE_ANNOUNCE_RETRY_DELAY: '3' diff --git a/kubernetes/face-detection.config-map.yml b/kubernetes/face-detection.config-map.yml deleted file mode 100644 index 41e3b20..0000000 --- a/kubernetes/face-detection.config-map.yml +++ /dev/null @@ -1,11 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: face-detection-config - labels: - app: face-detection -data: - ENVIRONMENT: development - LOG_LEVEL: debug - ENGINE_URLS: '["http://core-engine-service:8080"]' - SERVICE_URL: http://face-detection-service:8686 diff --git a/kubernetes/face-detection.ingress.yml b/kubernetes/face-detection.ingress.yml deleted file mode 100644 index bcd6382..0000000 --- a/kubernetes/face-detection.ingress.yml +++ /dev/null @@ -1,22 +0,0 @@ -apiVersion: networking.k8s.io/v1 -kind: Ingress -metadata: - name: face-detection-ingress - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "16m" - nginx.org/client-max-body-size: "16m" -spec: - rules: - - host: face-detection-swiss-ai-center.kube.isc.heia-fr.ch - http: - paths: - - path: / - pathType: Prefix - backend: - service: - name: face-detection-service - port: - number: 80 - tls: - - hosts: - - face-detection-swiss-ai-center.kube.isc.heia-fr.ch diff --git a/kubernetes/face-detection.stateful.yml b/kubernetes/face-detection.stateful.yml deleted file mode 100644 index 151e336..0000000 --- a/kubernetes/face-detection.stateful.yml +++ /dev/null @@ -1,36 +0,0 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - # This name uniquely identifies the stateful set - name: face-detection-stateful - labels: - app: face-detection -spec: - serviceName: face-detection - replicas: 1 - selector: - matchLabels: - app: face-detection - template: - metadata: - labels: - app: face-detection - spec: - containers: - - name: face-detection - image: ghcr.io/swiss-ai-center/face-detection:latest - # If you build the image locally, change the next line to `imagePullPolicy: Never` - there is no need to pull the image - imagePullPolicy: Always - ports: - - name: http - containerPort: 80 - env: - - name: MAX_TASKS - value: "50" - - name: ENGINE_ANNOUNCE_RETRIES - value: "5" - - name: ENGINE_ANNOUNCE_RETRY_DELAY - value: "3" - envFrom: - - configMapRef: - name: face-detection-config diff --git a/kubernetes/ingress.yml b/kubernetes/ingress.yml new file mode 100644 index 0000000..fb2020a --- /dev/null +++ b/kubernetes/ingress.yml @@ -0,0 +1,22 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: my-service-ingress + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: "16m" + nginx.org/client-max-body-size: "16m" +spec: + rules: + - host: my-service.example.com + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: my-service-service + port: + number: 80 + tls: + - hosts: + - my-service.example.com diff --git a/kubernetes/face-detection.service.yml b/kubernetes/service.yml similarity index 66% rename from kubernetes/face-detection.service.yml rename to kubernetes/service.yml index 1285b18..2e8de0d 100644 --- a/kubernetes/face-detection.service.yml +++ b/kubernetes/service.yml @@ -1,13 +1,13 @@ apiVersion: v1 kind: Service metadata: - name: face-detection-service + name: my-service-service spec: type: ClusterIP ports: - name: http - port: 8686 + port: 9090 targetPort: 80 protocol: TCP selector: - app: face-detection + app: my-service diff --git a/kubernetes/stateful.yml b/kubernetes/stateful.yml new file mode 100644 index 0000000..72697dd --- /dev/null +++ b/kubernetes/stateful.yml @@ -0,0 +1,28 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: my-service-stateful + labels: + app: my-service +spec: + serviceName: my-service + replicas: 1 + selector: + matchLabels: + app: my-service + template: + metadata: + labels: + app: my-service + spec: + containers: + - name: my-service + image: ghcr.io/organization/my-service:latest + # If you build the image locally, change the next line to `imagePullPolicy: Never` - there is no need to pull the image + imagePullPolicy: Always + ports: + - name: http + containerPort: 80 + envFrom: + - configMapRef: + name: my-service-config