diff --git a/.github/workflows/deploy-to-openshift-dev.yml b/.github/workflows/deploy-to-openshift-dev.yml index 95c4971..6e18099 100644 --- a/.github/workflows/deploy-to-openshift-dev.yml +++ b/.github/workflows/deploy-to-openshift-dev.yml @@ -1,17 +1,17 @@ name: 1 DEV - Deploy Dynamics API env: - # 🖊️ EDIT your repository secrets to log into your OpenShift cluster and set up the context. + # EDIT your repository secrets to log into your OpenShift cluster and set up the context. # See https://github.com/redhat-actions/oc-login#readme for how to retrieve these values. # To get a permanent token, refer to https://github.com/redhat-actions/oc-login/wiki/Using-a-Service-Account-for-GitHub-Actions OPENSHIFT_SERVER: ${{ secrets.OPENSHIFT_SERVER }} OPENSHIFT_TOKEN: ${{ secrets.OPENSHIFT_TOKEN }} - # 🖊️ EDIT to set the kube context's namespace after login. Leave blank to use your user's default namespace. + # EDIT to set the kube context's namespace after login. Leave blank to use your user's default namespace. OPENSHIFT_NAMESPACE: ${{ secrets.OFM_NAMESPACE_NO_ENV }}-dev # SPLUNK_TOKEN: ${{ secrets.SPLUNK_TOKEN }} - # 🖊️ EDIT to change the image registry settings. + # EDIT to change the image registry settings. # Registries such as GHCR, Quay.io, and Docker Hub are supported. IMAGE_REGISTRY: ghcr.io/${{ github.repository_owner }} IMAGE_REGISTRY_USER: ${{ github.actor }} @@ -80,19 +80,19 @@ jobs: core.error(`Secret "${name}" is not set`); return true; } - core.info(`✔️ Secret "${name}" is set`); + core.info(`Secret "${name}" is set`); return false; }); if (missingSecrets.length > 0) { - core.setFailed(`❌ At least one required secret is not set in the repository. \n` + + core.setFailed(`At least one required secret is not set in the repository. \n` + "You can add it using:\n" + "GitHub UI: https://docs.github.com/en/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository \n" + "GitHub CLI: https://cli.github.com/manual/gh_secret_set \n" + "Also, refer to https://github.com/redhat-actions/oc-login#getting-started-with-the-action-or-see-example"); } else { - core.info(`✅ All the required secrets are set`); + core.info(`All the required secrets are set`); } - name: Check out repository @@ -146,7 +146,7 @@ jobs: oc login --token=${{ env.OPENSHIFT_TOKEN }} --server=${{ env.OPENSHIFT_SERVER }} oc project ${{ env.OPENSHIFT_NAMESPACE }} # Cancel any rollouts in progress - oc rollout cancel dc/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} 2> /dev/null \ + oc rollout cancel deployment/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} 2> /dev/null \ || true && echo "No rollout in progress" # Create the image stream if it doesn't exist @@ -156,7 +156,7 @@ jobs: # Process and apply deployment template oc process \ - -f tools/openshift/d365api.dc.yaml \ + -f tools/openshift/d365api.deployment.yaml \ -p APP_NAME=${{ env.APP_NAME }} \ -p REPO_NAME=${{ env.REPO_NAME }} \ -p BRANCH=${{ env.BRANCH }} \ @@ -205,11 +205,11 @@ jobs: ${{ secrets.D365_INVOICE_LINES_DISTRIBUTION_ACK }} # Start rollout (if necessary) and follow it - oc rollout latest dc/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} 2> /dev/null \ + oc rollout restart deployment/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} 2> /dev/null \ || true && echo "Rollout in progress" # Get status, returns 0 if rollout is successful - oc rollout status dc/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} + oc rollout status deployment/${{ env.APP_NAME }}-${{ env.APP_NAME_BACKEND }}-${{ env.APP_ENVIRONMENT }} - name: ZAP Scan uses: zaproxy/action-full-scan@v0.8.0 diff --git a/tools/openshift/d365api.deployment.yaml b/tools/openshift/d365api.deployment.yaml new file mode 100644 index 0000000..6eda3bd --- /dev/null +++ b/tools/openshift/d365api.deployment.yaml @@ -0,0 +1,191 @@ +--- +apiVersion: template.openshift.io/v1 +kind: Template +labels: + template: '${REPO_NAME}-template' +metadata: + name: '${REPO_NAME}-d365api-deployment' +objects: + - apiVersion: apps/v1 + kind: Deployment + metadata: + annotations: + openshift.io/generated-by: OpenShiftNewApp + labels: + app: '${APP_NAME}-d365api-${BRANCH}' + branch: '${BRANCH}' + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + spec: + replicas: ${{MIN_REPLICAS}} + selector: + matchLabels: + app: '${APP_NAME}-d365api-${BRANCH}' + strategy: + type: RollingUpdate + rollingUpdate: + maxUnavailable: 25% + maxSurge: 25% + template: + metadata: + annotations: + openshift.io/generated-by: OpenShiftNewApp + labels: + app: '${APP_NAME}-d365api-${BRANCH}' + spec: + containers: + - image: image-registry.openshift-image-registry.svc:5000/${NAMESPACE}/${REPO_NAME}api:${TAG} + imagePullPolicy: Always + volumeMounts: + # - name: tls-certs + # mountPath: '/etc/tls-certs' + # readOnly: true + - name: log-storage + mountPath: /logs + - name: config-env + mountPath: /app/appsettings.json + subPath: appsettings.json + livenessProbe: + initialDelaySeconds: 20 + failureThreshold: 5 + httpGet: + path: '/api/Health' + port: 5091 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + ports: + - containerPort: 5091 + protocol: TCP + - containerPort: 443 + protocol: TCP + readinessProbe: + initialDelaySeconds: 10 + failureThreshold: 5 + httpGet: + path: '/api/Health' + port: 5091 + scheme: HTTP + periodSeconds: 10 + successThreshold: 1 + timeoutSeconds: 5 + resources: + requests: + cpu: '${MIN_CPU}' + memory: '${MIN_MEM}' + limits: + cpu: '${MAX_CPU}' + memory: '${MAX_MEM}' + volumes: + - name: log-storage + emptyDir: {} + - name: config-env + configMap: + name: ofm-d365api-${ENVIRONMENT}-config-map + # - name: tls-certs + # secret: + # secretName: ofm-backend-cert + test: false + - apiVersion: v1 + kind: Service + metadata: + annotations: + service.alpha.openshift.io/serving-cert-secret-name: 'ofm-backend-cert' + openshift.io/generated-by: OpenShiftNewApp + labels: + app: '${APP_NAME}-d365api-${BRANCH}' + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + spec: + ports: + - name: 5091-tcp + port: 5091 + protocol: TCP + targetPort: 5091 + - name: 443-https + port: 443 + protocol: TCP + targetPort: 443 + selector: + app: '${APP_NAME}-d365api-${BRANCH}' + - apiVersion: v1 + kind: Route + metadata: + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + labels: + app: '${APP_NAME}-d365api-${BRANCH}' + annotations: + openshift.io/host.generated: 'true' + router.openshift.io/cookie-same-site: 'Strict' + haproxy.router.openshift.io/ip_whitelist: >- + ${HAPROXY_IP_WHITELIST} + spec: + to: + kind: Service + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + weight: 100 + port: + targetPort: 5091-tcp + tls: + termination: edge + insecureEdgeTerminationPolicy: Redirect + wildcardPolicy: None + - apiVersion: autoscaling/v2 + kind: HorizontalPodAutoscaler + metadata: + name: '${APP_NAME}-d365api-${ENVIRONMENT}-cpu-autoscaler' + spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: '${APP_NAME}-d365api-${ENVIRONMENT}' + subresource: scale + minReplicas: ${{MIN_REPLICAS}} + maxReplicas: ${{MAX_REPLICAS}} + metrics: + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: 90 +parameters: + - name: REPO_NAME + description: Application repository name + required: true + - name: BRANCH + description: Job identifier (i.e. 'pr-5' OR 'master') + required: true + - name: NAMESPACE + description: Target namespace reference (i.e. 'k8vopl-dev') + required: true + - name: ENVIRONMENT + description: The environment being created ('dev', 'test', 'uat', 'prod') + required: true + - name: APP_NAME + description: Application name + required: true + - name: TAG + description: The identifying tag for this specific deployment + required: true + - name: MIN_REPLICAS + description: The minimum amount of replicas + required: true + - name: MAX_REPLICAS + description: The maximum amount of replicas + required: true + - name: MIN_CPU + description: The minimum amount of cpu + required: true + - name: MAX_CPU + description: The maximum amount of cpu + required: true + - name: MIN_MEM + description: The minimum amount of memory + required: true + - name: MAX_MEM + description: The maximum amount of memory + required: true + - name: HAPROXY_IP_WHITELIST + description: List of ip addresses delimited by space for access to api. (ex. 12.12.123.12 13.13.123.13). use * to allow access to all. + required: true