Skip to content

GitHub Workflow

GitHub Workflow #2

Workflow file for this run

# 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