diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index da1a93e4404a..ca6d3747a764 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -138,7 +138,9 @@ jobs: platforms: linux/amd64,linux/arm64 file: ./docker/artemis/Dockerfile context: . - tags: ghcr.io/ls1intum/artemis:${{ steps.compute-tag.outputs.result }} + tags: | + ghcr.io/ls1intum/artemis:${{ steps.compute-tag.outputs.result }} + ghcr.io/ls1intum/artemis:${{ github.sha }} push: true cache-from: type=gha cache-to: type=gha,mode=min diff --git a/.github/workflows/helm_pr_deployment.yml b/.github/workflows/helm_pr_deployment.yml new file mode 100644 index 000000000000..2730ef347238 --- /dev/null +++ b/.github/workflows/helm_pr_deployment.yml @@ -0,0 +1,100 @@ +name: Deploy PR to Kubernetes + +on: + pull_request: + types: [opened, synchronize, reopened, labeled] + +jobs: + deploy: + if: ${{ github.event.pull_request.head.repo.full_name == 'ls1intum/Artemis' && contains(github.event.pull_request.labels.*.name, 'deploy:k8s') }} + runs-on: ubuntu-latest + environment: + name: k8s + url: https://pr${{ github.event.pull_request.number }}.artemis-k8s.ase.cit.tum.de + concurrency: + group: k8s-pr${{ github.event.pull_request.number }} + cancel-in-progress: true + + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Setup Helm + uses: azure/setup-helm@v3 + with: + version: v3.15.0 + + - name: Setup Kubectl + uses: azure/setup-kubectl@v3 + with: + version: v1.30.1 + + - name: Authenticate to Kubernetes cluster + run: | + mkdir -p $HOME/.kube + echo "${{ secrets.KUBECONFIG }}" > "$HOME/.kube/config" + + - name: Get branch name + id: branch + run: echo "BRANCH_NAME=\"${GITHUB_REF#refs/heads/}\"" >> "$GITHUB_ENV" + + - name: Determine tag + id: determine-tag + run: echo "SEM_VERSION=0.0.0-pr${{ github.event.pull_request.number }}" >> "$GITHUB_ENV" + + - name: Update chart dependencies + run: helm dependency update helm/artemis + + - name: Chart | Push + uses: appany/helm-oci-chart-releaser@v0.3.0 + with: + name: artemis + repository: ${{ github.repository_owner }}/helm + tag: ${{ env.SEM_VERSION }} + path: helm/artemis + registry: ghcr.io + registry_username: ${{ github.repository_owner }} + registry_password: ${{ secrets.GITHUB_TOKEN }} + update_dependencies: 'true' + + - name: Deploy Helm chart + run: | + helm upgrade --install artemis \ + oci://ghcr.io/${{ github.repository_owner }}/helm/artemis --version ${{ env.SEM_VERSION }} \ + --namespace artemis-pr${{ github.event.pull_request.number }} --create-namespace \ + --set artemis.ingress.className="" \ + --set artemis.ingress.annotations.cert-manager\\.io/cluster-issuer="letsencrypt-prod" \ + --set artemis.ingress.annotations.spec\\.ingressClassName=nginx \ + --set-string artemis.ingress.annotations.kubernetes\\.io/tls-acme="true" \ + --set-string artemis.ingress.annotations.nginx\\.ingress\\.kubernetes\\.io/ssl-redirect="true" \ + --set artemis.ingress.hosts[0].host=pr${{ github.event.pull_request.number }}.artemis-k8s.ase.cit.tum.de \ + --set artemis.ingress.hosts[0].paths[0].path="/" \ + --set artemis.ingress.hosts[0].paths[0].pathType=ImplementationSpecific \ + --set artemis.ingress.tls[0].secretName=artemis-pr${{ github.event.pull_request.number }}-tls \ + --set artemis.ingress.tls[0].hosts[0]=pr${{ github.event.pull_request.number }}.artemis-k8s.ase.cit.tum.de \ + --set application.registry.jwt=${{ secrets.REGISTRY_JWT }} \ + --set application.versioncontrol.url="https://pr${{ github.event.pull_request.number }}.artemis-k8s.ase.cit.tum.de" \ + --set application.userManagement.internalAdmin.username=admin \ + --set application.userManagement.internalAdmin.password=${{ secrets.ADMIN_PW }} \ + --set application.operator.name="Technical University of Munich" \ + --set application.operator.admin_name="Stephan Krusche" \ + --set artemisVersion=${{ github.sha }} \ + --timeout 15m \ + --wait + + - name: Post Deployment Comment + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = context.issue.number; + + github.rest.issues.createComment({ + ...context.repo, + issue_number: prNumber, + body: ` + :rocket: Deployed **PR #${prNumber}** to https://pr${prNumber}.artemis-k8s.ase.cit.tum.de + + :hourglass_flowing_sand: It might take up to **10 minutes** to fully start up. + ` + }); diff --git a/.github/workflows/helm_pr_deployment_delete.yml b/.github/workflows/helm_pr_deployment_delete.yml new file mode 100644 index 000000000000..871e8f6e64a6 --- /dev/null +++ b/.github/workflows/helm_pr_deployment_delete.yml @@ -0,0 +1,40 @@ +name: Cleanup PR Deployment from Kubernetes + +on: + pull_request: + types: [closed] + +jobs: + destroy: + if: ${{ github.event.pull_request.head.repo.full_name == 'ls1intum/Artemis' && contains(github.event.pull_request.labels.*.name, 'deploy:k8s') }} + runs-on: ubuntu-latest + environment: + name: k8s + url: https://pr${{ github.event.pull_request.number }}.artemis-k8s.ase.cit.tum.de + concurrency: + group: k8s-pr${{ github.event.pull_request.number }} + cancel-in-progress: true + + steps: + - name: Setup Helm + uses: azure/setup-helm@v3 + with: + version: v3.15.0 + + - name: Setup Kubectl + uses: azure/setup-kubectl@v3 + with: + version: v1.30.1 + + - name: Authenticate to Kubernetes cluster + run: | + mkdir -p $HOME/.kube + echo "${{ secrets.KUBECONFIG }}" > "$HOME/.kube/config" + + - name: Delete Helm release + run: | + helm uninstall artemis --namespace artemis-pr${{ github.event.pull_request.number }} + + - name: Delete Kubernetes namespace + run: | + kubectl delete namespace artemis-pr${{ github.event.pull_request.number }} diff --git a/docs/dev/testservers.rst b/docs/dev/testservers.rst index 3e43a722747e..1f79619c5864 100644 --- a/docs/dev/testservers.rst +++ b/docs/dev/testservers.rst @@ -53,6 +53,9 @@ Test Servers | | - 1 Node | | | | | | - LTI | | | | +--------------------------------------------+-----------------------------+----------------+---------------------+----------------+ +| https://pr*.artemis-k8s.ase.cit.tum.de | - Integrated Code Lifecycle | GitHub | - Admin | Always | +| | - MySQL | | | | ++--------------------------------------------+-----------------------------+----------------+---------------------+----------------+ | **Legacy Testservers**: See on confluence below | +--------------------------------------------+-----------------------------+----------------+---------------------+----------------+ @@ -111,6 +114,22 @@ GitHub Deployment .. figure:: testservers/github/remove-lock-label.png :alt: GitHub Actions UI: Remove lock label +GitHub Deployment +----------------- + +1. Label your PR with deploy:k8s to initialize a deployment to Kubernetes. + +2. Once the server is deployed you get a message from GitHub Actions + + .. figure:: testservers/github/k8s-deploy-complete.png + :alt: GitHub Actions Comment: successful deployment + +2. Perform your testing + + a) For logs, log in to Rancher: https://rancher.ase.cit.tum.de + +3. As soon as you're done with this PR, close or merge it and the deployment will be destroyed. Don't remove the label! + Bamboo Deployment ----------------- 1. In your Pull Request on GitHub, scroll all the way down to the build status. diff --git a/docs/dev/testservers/github/k8s-deploy-complete.png b/docs/dev/testservers/github/k8s-deploy-complete.png new file mode 100644 index 000000000000..1525edd53a3b Binary files /dev/null and b/docs/dev/testservers/github/k8s-deploy-complete.png differ diff --git a/helm/.gitignore b/helm/.gitignore new file mode 100644 index 000000000000..ebf1d3dceb80 --- /dev/null +++ b/helm/.gitignore @@ -0,0 +1 @@ +charts diff --git a/helm/artemis/Chart.lock b/helm/artemis/Chart.lock new file mode 100644 index 000000000000..b06fedf261ba --- /dev/null +++ b/helm/artemis/Chart.lock @@ -0,0 +1,9 @@ +dependencies: +- name: prometheus-adapter + repository: https://prometheus-community.github.io/helm-charts + version: 3.4.1 +- name: prometheus + repository: https://prometheus-community.github.io/helm-charts + version: 15.18.0 +digest: sha256:9eb272bb161e9a4bf9fff7ec31a7719664ff2dce11e28be0d94a83bded0cffa1 +generated: "2024-08-10T17:33:10.801079972+02:00" diff --git a/helm/artemis/Chart.yaml b/helm/artemis/Chart.yaml new file mode 100644 index 000000000000..dcbf0f0c3ec1 --- /dev/null +++ b/helm/artemis/Chart.yaml @@ -0,0 +1,46 @@ +apiVersion: v2 +name: artemis +description: A Helm chart for Artemis + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +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/) +#TODO: figure out how and when this is updated +version: 1.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. +# It is recommended to use it with quotes. +appVersion: "7.5.0" + + +sources: + - https://github.com/ls1intum/Artemis + - https://github.com/ls1intum/artemis-helm + +maintainers: + - name: Matthias Linhuber + email: matthias.linhuber@tum.de + +icon: "https://github.com/ls1intum/Artemis/blob/develop/src/main/resources/public/images/logo.png" + +dependencies: + - name: prometheus-adapter + repository: https://prometheus-community.github.io/helm-charts + version: 3.4.1 + condition: artemis.autoscaler.customPrometheus + - name: prometheus + repository: https://prometheus-community.github.io/helm-charts + version: 15.18.0 + condition: artemis.autoscaler.customPrometheus diff --git a/helm/artemis/templates/NOTES.txt b/helm/artemis/templates/NOTES.txt new file mode 100644 index 000000000000..0e645db2d7af --- /dev/null +++ b/helm/artemis/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.artemis.ingress.enabled }} +{{- range $host := .Values.artemis.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.artemis.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.artemis.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "artemis.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.artemis.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "artemis.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "artemis.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.artemis.service.port }} +{{- else if contains "ClusterIP" .Values.artemis.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "artemis.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/helm/artemis/templates/_helpers.tpl b/helm/artemis/templates/_helpers.tpl new file mode 100644 index 000000000000..bedefa04602f --- /dev/null +++ b/helm/artemis/templates/_helpers.tpl @@ -0,0 +1,82 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "artemis.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "artemis.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "artemis.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "artemis.labels" -}} +helm.sh/chart: {{ include "artemis.chart" . }} +{{ include "artemis.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "artemis.selectorLabels" -}} +app.kubernetes.io/name: {{ include "artemis.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "artemis.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "artemis.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{/* +Generate common Artemis java spring profiles +*/}} +{{- define "artemis.springprofiles" -}} +prod,artemis,decoupling +{{- if .Values.application.userManagement.provider -}} +,{{ .Values.application.userManagement.provider }} +{{- end }} +{{- if .Values.application.userManagement.ldap.enabled -}} +,ldap +{{- end }} +{{- if .Values.application.versioncontrol.provider -}} +,{{ .Values.application.versioncontrol.provider }} +{{- end }} +{{- if .Values.application.continuousintegration.provider -}} +,{{ .Values.application.continuousintegration.provider }} +{{- end }} +{{- end }} diff --git a/helm/artemis/templates/autoscaler/horizontal-pod-autoscaler.yml b/helm/artemis/templates/autoscaler/horizontal-pod-autoscaler.yml new file mode 100644 index 000000000000..bb2318e2ec47 --- /dev/null +++ b/helm/artemis/templates/autoscaler/horizontal-pod-autoscaler.yml @@ -0,0 +1,41 @@ +{{- if .Values.artemis.autoscaler.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "artemis.fullname" . }} + labels: + {{- include "artemis.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "artemis.fullname" . }} + minReplicas: {{ .Values.artemis.autoscaler.minReplicas }} + maxReplicas: {{ .Values.artemis.autoscaler.maxReplicas }} + {{- with .Values.artemis.autoscaler.behavior }} + behavior: + {{- toYaml . | nindent 8 }} + {{- end }} + metrics: + {{- if .Values.artemis.autoscaler.metrics.usersPerInstance }} + - type: Pods + pods: + metric: + name: artemis_instance_websocket_users + target: + type: AverageValue + averageValue: {{ .Values.artemis.autoscaler.metrics.usersPerInstance }} + {{- end }} + {{- range .Values.artemis.autoscaler.metrics.externalMetrics }} + - type: External + external: + metric: + name: {{ .name }} + selector: + matchLabels: + {{- toYaml .labels | nindent 12 }} + target: + type: AverageValue + averageValue: {{ .targetValue }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/helm/artemis/templates/configmaps/activemq-broker-configmap.yml b/helm/artemis/templates/configmaps/activemq-broker-configmap.yml new file mode 100644 index 000000000000..3b4a5226b4be --- /dev/null +++ b/helm/artemis/templates/configmaps/activemq-broker-configmap.yml @@ -0,0 +1,74 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: activemq-broker-configmap +data: + broker.xml: | + + + + + ActiveMQ Kubernetes + + 10 + + 100 + + + + tcp://0.0.0.0:61616?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;amqpMinLargeMessageSize=102400;protocols=CORE,AMQP,STOMP,HORNETQ,MQTT,OPENWIRE;useEpoll=true;amqpCredits=1000;amqpLowCredits=300;amqpDuplicateDetection=true + + + tcp://0.0.0.0:61613?tcpSendBufferSize=1048576;tcpReceiveBufferSize=1048576;protocols=STOMP;useEpoll=true;heartBeatToConnectionTtlModifier=6 + + + + tcp://0.0.0.0:61616 + + + + true + / + # + * + + + + + + + + + + + + + + + + + + + + + + + DLQ + ExpiryQueue + 0 + + -1 + 10 + PAGE + true + true + true + true + + + + diff --git a/helm/artemis/templates/configmaps/artemis-ci-configmap.yml b/helm/artemis/templates/configmaps/artemis-ci-configmap.yml new file mode 100644 index 000000000000..ed5c8c6bd9bb --- /dev/null +++ b/helm/artemis/templates/configmaps/artemis-ci-configmap.yml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: artemis-ci-configmap +data: + artemis.continuous-integration.auth-token-value: {{ .Values.application.continuousintegration.artemis_authentication_token_value | quote }} + artemis.continuous-integration.specify-concurrent-builds: {{ .Values.application.continuousintegration.specify_concurrent_builds | quote }} + artemis.continuous-integration.concurrent-build-size: {{ .Values.application.continuousintegration.concurrent_build_size | quote }} + artemis.continuous-integration.specify-thread-pool-size: {{ .Values.application.continuousintegration.specify_thread_pool_size | quote }} + artemis.continuous-integration.image-cleanup.enabled: {{ .Values.application.continuousintegration.image_cleanup.enabled | quote }} + artemis.continuous-integration.image-cleanup.expiry-days: {{ .Values.application.continuousintegration.image_cleanup.expiry_days | quote }} + artemis.continuous-integration.image-cleanup.cleanup-schedule-time: {{ .Values.application.continuousintegration.image_cleanup.cleanup_schedule_time | quote }} diff --git a/helm/artemis/templates/configmaps/artemis-configmap.yml b/helm/artemis/templates/configmaps/artemis-configmap.yml new file mode 100644 index 000000000000..5b7f1b034c09 --- /dev/null +++ b/helm/artemis/templates/configmaps/artemis-configmap.yml @@ -0,0 +1,29 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: artemis-app +data: + SPRING_DATASOURCE_URL: jdbc:mysql://artemis-mysql/artemis?useUnicode=true&characterEncoding=utf8&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC&createDatabaseIfNotExist=true + SPRING_PROFILES_ACTIVE: {{ include "artemis.springprofiles" .}} + INFO_OPERATORNAME: {{ .Values.application.operator.name }} + INFO_OPERATORADMINNAME: {{ .Values.application.operator.admin_name }} + artemis.file-upload-path: {{ .Values.artemis.volumes.mountPath }}/uploads + artemis.submission-export-path: {{ .Values.artemis.volumes.mountPath }}/exports + artemis.repo-clone-path: {{ .Values.artemis.volumes.mountPath }}/repos + artemis.repo-download-clone-path: {{ .Values.artemis.volumes.mountPath }}/repos-download + eureka.client.enabled: "true" + eureka.instance.instanceId: "${HOSTNAME}" + spring.hazelcast.interface: "${MY_POD_IP}" + spring.websocket.broker.addresses: "{{ .Values.broker.service.name }}:{{ .Values.broker.service.port }}" + spring.artemis.mode: "native" + spring.artemis.broker-url: "tcp://{{ .Values.broker.service.name }}:61616" + logging.level.reactor.netty.transport.TransportConnector: "DEBUG" + {{- with (first .Values.artemis.ingress.hosts) }} + server.url: https://{{ .host }} + {{- end }} + EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE: http://admin:${spring.security.user.password}@{{ .Values.registry.service.name }}:{{ .Values.registry.service.port }}/eureka/ + {{- if .Values.artemis.autoscaler.enabled }} + management.metrics.export.prometheus.enabled: "true" + spring.prometheus.monitoringIp: {{ .Values.artemis.autoscaler.monitoringIp }} + {{- end }} + jhipster.security.authentication.jwt.base64-secret: {{ required "Registry JWT is required!" .Values.application.registry.jwt | b64enc | quote }} \ No newline at end of file diff --git a/helm/artemis/templates/configmaps/artemis-mysql-configmap.yml b/helm/artemis/templates/configmaps/artemis-mysql-configmap.yml new file mode 100644 index 000000000000..59efc443827f --- /dev/null +++ b/helm/artemis/templates/configmaps/artemis-mysql-configmap.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +data: + MYSQL_ROOT_PASSWORD: "" + MYSQL_DATABASE: "Artemis" + MYSQL_ALLOW_EMPTY_PASSWORD: "yes" +kind: ConfigMap +metadata: + name: artemis-mysql diff --git a/helm/artemis/templates/configmaps/artemis-usermanagement-configmap.yml b/helm/artemis/templates/configmaps/artemis-usermanagement-configmap.yml new file mode 100644 index 000000000000..42bf70cefc44 --- /dev/null +++ b/helm/artemis/templates/configmaps/artemis-usermanagement-configmap.yml @@ -0,0 +1,20 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: artemis-usermanagement-configmap +data: + {{- if and .Values.application.userManagement.useExternal ( eq .Values.application.userManagement.provider "jira") }} + artemis.user-management.use-external: "true" + artemis.user-management.external.url: {{ required "Jira URL is required" .Values.application.userManagement.jira.url | quote }} + artemis.user-management.external.admin-group-name: {{ .Values.application.userManagement.jira.adminGroupName | quote }} + {{- else }} + artemis.user-management.use-external: "false" + {{- end }} + {{- with .Values.application.userManagement.ldap }} + {{- if .enabled }} + artemis.user-management.ldap.url: {{ required "LDAP URL is required" .url | quote }} + artemis.user-management.ldap.base: {{ required "LDAP BASE is required" .base | quote }} + artemis.user-management.ldap.allowed-username-pattern: {{ .allowedUsernamePattern | squote }} + management.health.ldap.enabled: "true" + {{- end }} + {{- end }} diff --git a/helm/artemis/templates/configmaps/artemis-vcs-configmap.yml b/helm/artemis/templates/configmaps/artemis-vcs-configmap.yml new file mode 100644 index 000000000000..d2fb2b5b5832 --- /dev/null +++ b/helm/artemis/templates/configmaps/artemis-vcs-configmap.yml @@ -0,0 +1,10 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: artemis-vcs-configmap +data: + artemis.version-control.url: {{ .Values.application.versioncontrol.url | quote }} + artemis.version-control.local-vcs-repo-path: {{ .Values.application.versioncontrol.local_vcs_repo_path | quote }} + artemis.version-control.ssh_key_path: {{ .Values.application.versioncontrol.ssh_key_path | quote }} + artemis.version-control.build-agent-git-username: {{ .Values.application.versioncontrol.build_agent_git_credentials.user | quote }} + artemis.version-control.build-agent-git-password: {{ .Values.application.versioncontrol.build_agent_git_credentials.password | quote }} diff --git a/helm/artemis/templates/configmaps/jhipster-registry-configmap.yml b/helm/artemis/templates/configmaps/jhipster-registry-configmap.yml new file mode 100644 index 000000000000..c4c01f19e2ac --- /dev/null +++ b/helm/artemis/templates/configmaps/jhipster-registry-configmap.yml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jhipster-registry-configmap +data: + application.yml: |- + configserver: + name: JHipster Registry + status: Connected to the JHipster Registry running in Kubernetes + eureka: + client: + initial-instance-info-replication-interval-seconds: 15 + instance-info-replication-interval-seconds: 15 + registry-fetch-interval-seconds: 15 + fetch-registry: true + register-with-eureka: true + eureka-service-url-poll-interval-seconds: 15 + instance: + lease-renewal-interval-in-seconds: 10 + registry-default-open-for-traffic-count: 0 + jhipster: + security: + authentication: + jwt: + # This is bad practice, but this value cannot be handed to the registry via the environment. Needs further investigation + base64-secret: {{ required "Registry JWT is required!" .Values.application.registry.jwt | b64enc | quote }} + # app specific configuration + jhipster-registry.yml: |- + eureka: + client: + service-url: + defaultZone: http://admin:${spring.security.user.password}@{{ .Values.registry.service.name }}:{{ .Values.registry.service.port }}/eureka/ diff --git a/helm/artemis/templates/configmaps/jhipster-registry-env-configmap.yml b/helm/artemis/templates/configmaps/jhipster-registry-env-configmap.yml new file mode 100644 index 000000000000..b1b94fd695f3 --- /dev/null +++ b/helm/artemis/templates/configmaps/jhipster-registry-env-configmap.yml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: jhipster-registry-env-configmap +data: + SPRING_PROFILES_ACTIVE: prod,k8s + SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_TYPE: native + SPRING_CLOUD_CONFIG_SERVER_COMPOSITE_0_SEARCH_LOCATIONS: file:./central-config + K8S_CONFIG_PATH: /central-config/ diff --git a/helm/artemis/templates/deployments/_artemis-deployment.yml b/helm/artemis/templates/deployments/_artemis-deployment.yml new file mode 100644 index 000000000000..613a9e4ff80e --- /dev/null +++ b/helm/artemis/templates/deployments/_artemis-deployment.yml @@ -0,0 +1,112 @@ +{{ define "deployment-template" }} + {{- if not .Values.artemis.autoscaler.enabled }} + replicas: {{ .Values.artemis.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "artemis.selectorLabels" . | nindent 6 }} + {{- if (.Args).profile }} + profile: "{{ .Args.profile }}" + {{- end }} + + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + + template: + metadata: + {{- with .Values.artemis.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "artemis.selectorLabels" . | nindent 8 }} + {{- if (.Args).profile }} + profile: "{{ .Args.profile }}" + {{- end }} + spec: + securityContext: {} + restartPolicy: Always + securityContext: + # Make sure that the container can read and write the PVC + # The Artemis executable is started with an unprivileged user (UID 1000) + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + containers: + - name: "{{ .Chart.Name }}-{{ ((.Args).profile | default "all") }}" + image: "{{ .Values.artemis.image.repository }}{{ .Values.artemis.image.name }}:{{ .Values.artemisVersion | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.artemis.image.pullPolicy }} + + # We hand the pod IP to the container env here to build the hazelcast cluster. + # The MY_POD_IP variable is used in the artemis configmap + env: + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SPRING_PROFILES_INCLUDE + value: {{ ((.Args).profile | default "") | quote }} + envFrom: + - configMapRef: + name: artemis-usermanagement-configmap + - configMapRef: + name: artemis-vcs-configmap + - configMapRef: + name: artemis-ci-configmap + - configMapRef: + name: artemis-app + optional: false + - secretRef: + name: artemis-usermanagement-secrets + - secretRef: + name: artemis-secrets + ports: + - name: http + containerPort: 8080 + protocol: TCP + securityContext: + {{- toYaml .Values.artemis.podSecurityContext | nindent 14 }} + resources: + {{- toYaml .Values.artemis.resources | nindent 12 }} + volumeMounts: + - mountPath: {{ .Values.artemis.volumes.mountPath }} + name: artemis-volume + + {{- with .Values.artemis.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.artemis.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.artemis.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + + initContainers: + - name: init-ds + image: busybox:latest + command: + - '/bin/sh' + - '-c' + - | + while true + do + rt=$(nc -z -w 1 artemis-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done + + volumes: + - name: artemis-volume + persistentVolumeClaim: + claimName: {{ .Values.artemis.volumes.name }} +{{end}} \ No newline at end of file diff --git a/helm/artemis/templates/deployments/activemq-broker.yml b/helm/artemis/templates/deployments/activemq-broker.yml new file mode 100644 index 000000000000..b232a9d191da --- /dev/null +++ b/helm/artemis/templates/deployments/activemq-broker.yml @@ -0,0 +1,60 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: activemq-broker + labels: + app: activemq-broker +spec: + progressDeadlineSeconds: 600 + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + app: activemq-broker + strategy: + rollingUpdate: + maxSurge: 1 + maxUnavailable: 0 + type: RollingUpdate + template: + metadata: + labels: + app: activemq-broker + spec: + restartPolicy: Always + containers: + - name: activemq-artemis + image: "{{ .Values.broker.image.repository }}{{ .Values.broker.image.name }}:{{ .Values.broker.image.version }}" + imagePullPolicy: Always + envFrom: + - secretRef: + name: activemq-broker-secrets + optional: false + - configMapRef: + name: activemq-broker-configmap + optional: false + + ports: + - name: activemq-stomp + containerPort: 61616 + protocol: TCP + + - name: activemq-jms + containerPort: 61613 + protocol: TCP + + command: ["/bin/bash", "-c", "ls -la && /opt/activemq-artemis/bin/artemis create --user ${ARTEMIS_USER} --password ${ARTEMIS_PASSWORD} --silent ${LOGIN_OPTION} ${EXTRA_ARGS} . && cp /tmp/broker.xml /var/lib/artemis-instance/etc/broker.xml && pwd && ls -la && echo test && ./bin/artemis run"] + # args: ["HOSTNAME", "KUBERNETES_PORT", "PATH"] + + volumeMounts: + - name: activemq-broker-configmap + mountPath: /tmp/broker.xml + subPath: broker.xml + + resources: + {{- toYaml .Values.broker.resources | nindent 12 }} + + volumes: + - name: activemq-broker-configmap + configMap: + name: activemq-broker-configmap \ No newline at end of file diff --git a/helm/artemis/templates/deployments/artemis-deployment-profile.yaml b/helm/artemis/templates/deployments/artemis-deployment-profile.yaml new file mode 100644 index 000000000000..5554e3b0e74d --- /dev/null +++ b/helm/artemis/templates/deployments/artemis-deployment-profile.yaml @@ -0,0 +1,12 @@ +{{- range .Values.artemis.profileDeployments }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "artemis.fullname" $ }}-{{ .profile }} + labels: + {{- include "artemis.labels" $ | nindent 4 }} + +spec: + {{- include "deployment-template" (merge (dict "Args" .) $ ) | nindent 4 }} +--- +{{ end }} \ No newline at end of file diff --git a/helm/artemis/templates/deployments/artemis-deployment.yaml b/helm/artemis/templates/deployments/artemis-deployment.yaml new file mode 100644 index 000000000000..33f6e6c97ff0 --- /dev/null +++ b/helm/artemis/templates/deployments/artemis-deployment.yaml @@ -0,0 +1,8 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "artemis.fullname" . }} + labels: + {{- include "artemis.labels" . | nindent 4 }} +spec: + {{- include "deployment-template" . | nindent 4 }} \ No newline at end of file diff --git a/helm/artemis/templates/ingresses/ingress.yaml b/helm/artemis/templates/ingresses/ingress.yaml new file mode 100644 index 000000000000..119bf94439e1 --- /dev/null +++ b/helm/artemis/templates/ingresses/ingress.yaml @@ -0,0 +1,65 @@ +{{- if .Values.artemis.ingress.enabled -}} +{{- $fullName := include "artemis.fullname" . -}} +{{- $svcPort := .Values.artemis.service.port -}} +{{- if and .Values.artemis.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.artemis.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.artemis.ingress.annotations "kubernetes.io/ingress.class" .Values.artemis.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "artemis.labels" . | nindent 4 }} + {{- with .Values.artemis.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.artemis.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.artemis.ingress.className }} + {{- end }} + {{- if .Values.artemis.ingress.tls }} + tls: + {{- range .Values.artemis.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.artemis.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + pathType: {{ .pathType }} + backend: + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- end }} + {{- range $profileDeploymentKey, $profileDeploymentValue := $.Values.artemis.profileDeployments }} + {{- range $profileDeploymentValue.apiPaths }} + - path: {{ . }} + pathType: "Exact" + backend: + service: + name: "{{ $fullName }}-{{ $profileDeploymentValue.profile }}" + port: + number: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/artemis/templates/monitors/podmonitor.yml b/helm/artemis/templates/monitors/podmonitor.yml new file mode 100644 index 000000000000..bbde3804aed3 --- /dev/null +++ b/helm/artemis/templates/monitors/podmonitor.yml @@ -0,0 +1,16 @@ +# This ServiceMonitor is used in combination with a Rancher cluster, where it is not possible to deploy a custom prometheus instance. +# This ServiceMonitor configures the existing instance to also monitor the artemis service. +{{- if and .Values.artemis.autoscaler.enabled (not .Values.artemis.autoscaler.customPrometheus) }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "artemis.fullname" . }} +spec: + selector: + matchLabels: + {{- include "artemis.selectorLabels" . | nindent 6 }} + endpoints: + - port: http + path: "/management/prometheus" + interval: "15s" +{{- end }} \ No newline at end of file diff --git a/helm/artemis/templates/pvc/artemis-mysql.yml b/helm/artemis/templates/pvc/artemis-mysql.yml new file mode 100644 index 000000000000..594e258fc463 --- /dev/null +++ b/helm/artemis/templates/pvc/artemis-mysql.yml @@ -0,0 +1,14 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: artemis-data +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: {{ .Values.database.volumes.size }} + {{- if ne .Values.database.volumes.storageClassName "" }} + storageClassName: {{ .Values.database.volumes.storageClassName }} + {{- end }} + volumeMode: Filesystem diff --git a/helm/artemis/templates/pvc/artemis.yml b/helm/artemis/templates/pvc/artemis.yml new file mode 100644 index 000000000000..f678cc21e1d0 --- /dev/null +++ b/helm/artemis/templates/pvc/artemis.yml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ .Values.artemis.volumes.name }} +spec: + {{- with .Values.artemis.volumes.accessModes }} + accessModes: + {{- toYaml . | nindent 4 }} + {{- end }} + resources: + requests: + storage: {{ .Values.artemis.volumes.size }} + {{- if ne .Values.artemis.volumes.storageClassName "" }} + storageClassName: {{ .Values.artemis.volumes.storageClassName }} + {{- end }} + + volumeMode: Filesystem diff --git a/helm/artemis/templates/secrets/activemq-broker-secrets.yml b/helm/artemis/templates/secrets/activemq-broker-secrets.yml new file mode 100644 index 000000000000..dfe5e2aa914f --- /dev/null +++ b/helm/artemis/templates/secrets/activemq-broker-secrets.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: activemq-broker-secrets +type: Opaque +data: + ARTEMIS_USER: {{ required "Broker user is required!" .Values.application.broker.username | b64enc | quote }} + ARTEMIS_PASSWORD: {{ required "Broker password is required!" .Values.application.broker.password | b64enc | quote }} diff --git a/helm/artemis/templates/secrets/artemis-secrets.yml b/helm/artemis/templates/secrets/artemis-secrets.yml new file mode 100644 index 000000000000..770fbd1bb5c5 --- /dev/null +++ b/helm/artemis/templates/secrets/artemis-secrets.yml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Secret +metadata: + name: artemis-secrets +type: Opaque +data: + artemis.athene.base64-secret: "" + artemis.lti.oauth-key: "" + artemis.lti.oauth-secret: "" + jhipster.registry.password: {{ required "Registry password is required" .Values.application.registry.password | b64enc | quote }} + spring.security.user.password: {{ required "Registry password is required" .Values.application.registry.password | b64enc | quote }} + spring.websocket.broker.username: {{ required "Broker user is required!" .Values.application.broker.username | b64enc | quote }} + spring.websocket.broker.password: {{ required "Broker password is required!" .Values.application.broker.password | b64enc | quote }} + spring.artemis.user: {{ required "Broker user is required!" .Values.application.broker.username | b64enc | quote }} + spring.artemis.password: {{ required "Broker password is required!" .Values.application.broker.password | b64enc | quote }} \ No newline at end of file diff --git a/helm/artemis/templates/secrets/artemis-usermanagement-secrets.yml b/helm/artemis/templates/secrets/artemis-usermanagement-secrets.yml new file mode 100644 index 000000000000..e1bfe9f67f3c --- /dev/null +++ b/helm/artemis/templates/secrets/artemis-usermanagement-secrets.yml @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Secret +metadata: + name: artemis-usermanagement-secrets +type: Opaque +data: + {{- if and .Values.application.userManagement.useExternal ( eq .Values.application.userManagement.provider "jira") }} + artemis.user-management.external.user: {{ required "Jira username is required" .Values.application.userManagement.jira.username | b64enc | quote }} + artemis.user-management.external.password: {{ required "Jira password is required" .Values.application.userManagement.jira.password | b64enc | quote }} + {{- end }} + {{- with .Values.application.userManagement.ldap }} + {{- if .enabled }} + artemis.user-management.ldap.user-dn: {{ required "LDAP USER-DN is required" .userDn | b64enc | quote }} + artemis.user-management.ldap.password: {{ required "LDAP PASSWORD is required" .password | b64enc | quote }} + {{- end }} + {{- end }} + artemis.user-management.internal-admin.username: {{ required "Internal admin username is required!" .Values.application.userManagement.internalAdmin.username | b64enc | quote}} + artemis.user-management.internal-admin.password: {{ required "Internal admin password is required!" .Values.application.userManagement.internalAdmin.password | b64enc | quote }} diff --git a/helm/artemis/templates/secrets/jhipster-registry-secrets.yml b/helm/artemis/templates/secrets/jhipster-registry-secrets.yml new file mode 100644 index 000000000000..8f1bc38ef9f5 --- /dev/null +++ b/helm/artemis/templates/secrets/jhipster-registry-secrets.yml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: jhipster-registry-secrets +type: Opaque +data: + SPRING_SECURITY_USER_PASSWORD: {{ required "Registry password is required" .Values.application.registry.password | b64enc | quote }} + JHIPSTER_REGISTRY_PASSWORD: {{ required "Registry password is required" .Values.application.registry.password | b64enc | quote }} diff --git a/helm/artemis/templates/services/activemq-broker-service.yml b/helm/artemis/templates/services/activemq-broker-service.yml new file mode 100644 index 000000000000..fcb79a2bfff8 --- /dev/null +++ b/helm/artemis/templates/services/activemq-broker-service.yml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ .Values.broker.service.name }} +spec: + selector: + app: activemq-broker + ports: + - name: stomp + port: {{ .Values.broker.service.port }} + protocol: TCP + targetPort: activemq-stomp + - name: jms + port: 61613 + protocol: TCP + targetPort: activemq-jms diff --git a/helm/artemis/templates/services/artemis-service-profile.yaml b/helm/artemis/templates/services/artemis-service-profile.yaml new file mode 100644 index 000000000000..8ff841df55f4 --- /dev/null +++ b/helm/artemis/templates/services/artemis-service-profile.yaml @@ -0,0 +1,23 @@ +{{- range .Values.artemis.profileDeployments }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "artemis.fullname" $ }}-{{.profile}} + labels: + {{- include "artemis.labels" $ | nindent 4 }} + {{- with $.Values.artemis.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ $.Values.artemis.service.type }} + ports: + - port: {{ $.Values.artemis.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "artemis.selectorLabels" $ | nindent 4 }} + profile: "{{.profile}}" +--- +{{end}} \ No newline at end of file diff --git a/helm/artemis/templates/services/artemis-service.yaml b/helm/artemis/templates/services/artemis-service.yaml new file mode 100644 index 000000000000..0c33b4b65f8b --- /dev/null +++ b/helm/artemis/templates/services/artemis-service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "artemis.fullname" . }} + labels: + {{- include "artemis.labels" . | nindent 4 }} + {{- with .Values.artemis.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.artemis.service.type }} + ports: + - port: {{ .Values.artemis.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "artemis.selectorLabels" . | nindent 4 }} diff --git a/helm/artemis/templates/services/jhipster-registry-service.yaml b/helm/artemis/templates/services/jhipster-registry-service.yaml new file mode 100644 index 000000000000..b856607a2a86 --- /dev/null +++ b/helm/artemis/templates/services/jhipster-registry-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: jhipster-registry-service +spec: + type: {{ .Values.registry.service.type }} + ports: + - name: jhipster-registry-port + port: {{ .Values.registry.service.port }} + targetPort: registry-p-port + protocol: TCP + selector: + app: jhipster-registry diff --git a/helm/artemis/templates/services/mysql-service.yaml b/helm/artemis/templates/services/mysql-service.yaml new file mode 100644 index 000000000000..db5235b28c90 --- /dev/null +++ b/helm/artemis/templates/services/mysql-service.yaml @@ -0,0 +1,13 @@ +apiVersion: v1 +kind: Service +metadata: + name: artemis-mysql +spec: + type: ClusterIP + ports: + - port: 3306 + targetPort: 3306 + protocol: TCP + name: mysql + selector: + workload.user.cattle.io/workloadselector: statefulSet-artemis-artemis-mysql diff --git a/helm/artemis/templates/statefulsets/artemis-mysql.yml b/helm/artemis/templates/statefulsets/artemis-mysql.yml new file mode 100644 index 000000000000..7e2be18ab8c3 --- /dev/null +++ b/helm/artemis/templates/statefulsets/artemis-mysql.yml @@ -0,0 +1,66 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + annotations: + field.cattle.io/creatorId: user-nxxf9 + labels: + cattle.io/creator: norman + workload.user.cattle.io/workloadselector: statefulSet-artemis-artemis-mysql + name: artemis-mysql +spec: + podManagementPolicy: OrderedReady + replicas: 1 + revisionHistoryLimit: 10 + selector: + matchLabels: + workload.user.cattle.io/workloadselector: statefulSet-artemis-artemis-mysql + serviceName: artemis-mysql + template: + metadata: + labels: + workload.user.cattle.io/workloadselector: statefulSet-artemis-artemis-mysql + spec: + containers: + - args: + - mysqld + - --lower_case_table_names=1 + - --skip-ssl + - --character_set_server=utf8mb4 + - --collation-server=utf8mb4_unicode_ci + - --explicit_defaults_for_timestamp + envFrom: + - configMapRef: + name: artemis-mysql + image: mysql:8.0.27 + imagePullPolicy: IfNotPresent + name: artemis-mysql + ports: + - containerPort: 3306 + name: 3306tcp2 + protocol: TCP + resources: + {{- toYaml .Values.database.resources | nindent 12 }} + securityContext: + allowPrivilegeEscalation: false + privileged: false + readOnlyRootFilesystem: false + runAsNonRoot: false + stdin: true + terminationMessagePath: /dev/termination-log + terminationMessagePolicy: File + tty: true + volumeMounts: + - mountPath: /var/lib/mysql/ + name: artemis-data + dnsConfig: {} + dnsPolicy: ClusterFirst + restartPolicy: Always + schedulerName: default-scheduler + securityContext: {} + terminationGracePeriodSeconds: 30 + volumes: + - name: artemis-data + persistentVolumeClaim: + claimName: artemis-data + updateStrategy: + type: RollingUpdate diff --git a/helm/artemis/templates/statefulsets/artemis-statefulset.yaml b/helm/artemis/templates/statefulsets/artemis-statefulset.yaml new file mode 100644 index 000000000000..7e9e986c705e --- /dev/null +++ b/helm/artemis/templates/statefulsets/artemis-statefulset.yaml @@ -0,0 +1,103 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "artemis.fullname" . }} + labels: + {{- include "artemis.labels" . | nindent 4 }} +spec: + serviceName: {{ include "artemis.fullname" . }} + replicas: 1 + selector: + matchLabels: + {{- include "artemis.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.artemis.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "artemis.selectorLabels" . | nindent 8 }} + spec: + securityContext: {} + restartPolicy: Always + securityContext: + # Make sure that the container can read and write the PVC + # The Artemis executable is started with an unprivileged user (UID 1000) + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.artemis.image.repository }}{{ .Values.artemis.image.name }}:{{ .Values.artemisVersion | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.artemis.image.pullPolicy }} + + # We hand the pod IP to the container env here to build the hazelcast cluster. + # The MY_POD_IP variable is used in the artemis configmap + env: + - name: MY_POD_IP + valueFrom: + fieldRef: + fieldPath: status.podIP + - name: SPRING_PROFILES_ACTIVE + value: core,scheduling,{{ include "artemis.springprofiles" .}} + envFrom: + - configMapRef: + name: artemis-usermanagement-configmap + - configMapRef: + name: artemis-vcs-configmap + - configMapRef: + name: artemis-ci-configmap + - configMapRef: + name: artemis-app + optional: false + - secretRef: + name: artemis-usermanagement-secrets + - secretRef: + name: artemis-secrets + ports: + - name: http + containerPort: 8080 + protocol: TCP + securityContext: + {{- toYaml .Values.artemis.podSecurityContext | nindent 14 }} + resources: + {{- toYaml .Values.artemis.resources | nindent 12 }} + volumeMounts: + - mountPath: {{ .Values.artemis.volumes.mountPath }} + name: artemis-volume + + {{- with .Values.artemis.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.artemis.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.artemis.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + + initContainers: + - name: init-ds + image: busybox:latest + command: + - '/bin/sh' + - '-c' + - | + while true + do + rt=$(nc -z -w 1 artemis-mysql 3306) + if [ $? -eq 0 ]; then + echo "DB is UP" + break + fi + echo "DB is not yet reachable;sleep for 10s before retry" + sleep 10 + done + + volumes: + - name: artemis-volume + persistentVolumeClaim: + claimName: {{ .Values.artemis.volumes.name }} diff --git a/helm/artemis/templates/statefulsets/jhipster-registry.yml b/helm/artemis/templates/statefulsets/jhipster-registry.yml new file mode 100644 index 000000000000..1303619a8f1a --- /dev/null +++ b/helm/artemis/templates/statefulsets/jhipster-registry.yml @@ -0,0 +1,50 @@ +# JHipster Registry HA cluster +# +# Note that as this is based on a StatefulSet, it will only work on Kubernetes >= 1.5 +# +# By default, the JHipster Registry and its UI is not accessible from outside the cluster for security reasons +# You can setup temporary access to it on localhost:8761 by running : +# kubectl port-forward jhipster-registry-0 8761 +# +# To scale your JHipster Registry cluster : +# In this file, change the value of spec.replicas and CLUSTER_SIZE to any value +# Apply the descriptor again : `kubectl apply -f jhipster-registry.yml` +# This will create new replicas with the correct CLUSTER_SIZE which is mandatory so that all Eureka server can connect directly to all the others. +# Then delete the previous replica pods one by one so tht they can be recreated with the correct CLUSTER_SIZE configuration. +# `kubectl delete pod jhipster-registry-0`, `kubectl delete pod jhipster-registry-1` +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: jhipster-registry +spec: + serviceName: {{ .Values.registry.service.name | quote }} + replicas: {{ .Values.registry.replicaCount }} + selector: + matchLabels: + app: jhipster-registry + template: + metadata: + labels: + app: jhipster-registry + spec: + terminationGracePeriodSeconds: 10 + containers: + - name: jhipster-registry + image: "{{ .Values.registry.image.repository }}{{ .Values.registry.image.name }}:{{ .Values.registry.image.version }}" + ports: + - name: registry-p-port + containerPort: 8761 + envFrom: + - configMapRef: + name: jhipster-registry-env-configmap + - secretRef: + name: jhipster-registry-secrets + volumeMounts: + - name: config-volume + mountPath: /central-config + resources: + {{- toYaml .Values.registry.resources | nindent 12 }} + volumes: + - name: config-volume + configMap: + name: jhipster-registry-configmap diff --git a/helm/artemis/templates/tests/test-connection.yaml b/helm/artemis/templates/tests/test-connection.yaml new file mode 100644 index 000000000000..87f669d221aa --- /dev/null +++ b/helm/artemis/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "artemis.fullname" . }}-test-connection" + labels: + {{- include "artemis.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "artemis.fullname" . }}:{{ .Values.artemis.service.port }}'] + restartPolicy: Never diff --git a/helm/artemis/values.yaml b/helm/artemis/values.yaml new file mode 100644 index 000000000000..19a88e046ac4 --- /dev/null +++ b/helm/artemis/values.yaml @@ -0,0 +1,252 @@ +# Default values for artemis. + +# Specify the Artemis version +# This value is used as docker image tag, so also "pr-1234" is a valid value here. +# See https://github.com/ls1intum/Artemis/pkgs/container/artemis/versions +artemisVersion: "7.5.0" + + +# Application specific configuration +application: + userManagement: + + # Initial Artemis admin account - Required! + internalAdmin: + username: + password: + + # Set true if external user management should be enabled + useExternal: false + + provider: "" + + # the whole section is optional: whether user details (such as the registration number) can be obtained from a LDAP service + ldap: + enabled: false + url: "" + userDn: "" + base: "" + password: "" + allowedUsernamePattern: '' + # allowedUsernamePattern: '^([a-z]{2}\d{2}[a-z]{3})$'zs # example for a TUM identifier, e.g. ab12cde + + operator: + name: "Example University Name" # FIXME: Set the name of your university + admin_name: "Max Mustermann" # FIXME: Set the name of the main admin + + # Local Version Control configuration + versioncontrol: + provider: "localvc" + url: "" + local_vcs_repo_path: /artemisdata/vcs/repo + ssh_key_path: /artemisdata/artemisdata/ssh-keys + build_agent_git_credentials: + user: "artemis-icl-build-agent" + password: "" + + + # Local Continuous Integration configuration + continuousintegration: + provider: "localci" + artemis_authentication_token_value: "demo" # FIXME: Set secure auth token + specify_concurrent_builds: true + concurrent_build_size: 3 + specify_thread_pool_size: false + image_cleanup: + enabled: true + expiry_days: 7 + cleanup_schedule_time: "0 0 3 * * *" + + + # Configuration of the jHipster Registry + registry: + jwt: + password: "SuperSecure" + + # ActiveMQ message broker configuration + broker: + username: "brokeruser" + password: "brokerpassword" + + +# Configuration for the artemis application server pods +artemis: + # Currently we only support 1 replica of artemis. This will change in the future + # Note that this value is ignored if the horizontal pod autoscaler is used + replicaCount: 0 + + image: + repository: "ghcr.io/ls1intum/" + name: "artemis" + pullPolicy: Always + + podAnnotations: + prometheus.io/path: /management/prometheus + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + + podSecurityContext: + allowPrivilegeEscalation: false + + securityContext: {} + + service: + type: ClusterIP + port: 8080 + + ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: artemis.example + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + # - secretName: chart-example-tls + # hosts: + # - example.com + + volumes: + name: artemis-pvc + accessModes: + - ReadWriteMany + size: 3Gi + storageClassName: "" + mountPath: "/artemisdata" + + resources: + requests: + memory: "2560Mi" + cpu: "1000m" + limits: + memory: "5120Mi" + cpu: "2000m" + + nodeSelector: {} + + tolerations: [] + + affinity: {} + + autoscaler: + # Whether the autoscaling should be used for the Artemis deployment + enabled: false + # Wether custom prometheus + prometheus adapter instances should be deployed. You have to provide a custom prometheus instance & configure it, if you set this value to true. + customPrometheus: false + # IP address range that should be allowed to query metrics (must include the IP of the deployed prometheus server) + monitoringIp: "0.0.0.0/0" + # Behavior of the autoscaler + behavior: {} + # Which metrics should be used for the scaling + metrics: + # Average number of users per instance that should be targeted - the autoscaler will scale according to this metrics + usersPerInstance: 100 + # External metrics: These metrics are not dependent on the individual Artemis instance but are the same across all instances. + # These metrics can be used for preemptive scaling + externalMetrics: + # Possible metrics: + # artemis.scheduled.{exams,exercises}.{due,release}.{count,student_multiplier,student_multiplier.active.14} + - name: "artemis_scheduled_exercises_release_student_multiplier" + targetValue: 50 # How many users should be targeted + # The labels define which metric should be used as multiple data points for the same name exist + labels: + exerciseType: "TEXT" # Only for exercise-metrics, one of TEXT, QUIZ, PROGRAMMING, MODELING, FILE_UPLOAD + range: "120" # in minutes, one of 5, 15, 30, 45, 60, 120 + # Minimum number of replicas + minReplicas: 1 + # Maximum number of replicas + maxReplicas: 5 + +database: + volumes: + size: 3Gi + storageClassName: "" + + resources: + requests: + memory: "512Mi" + cpu: "1000m" + limits: + memory: "1024Mi" + cpu: "2000m" + +registry: + replicaCount: 1 + + image: + # Leave empty to use the official image + repository: "" + name: "jhipster/jhipster-registry" + version: "v7.4.0" + pullPolicy: Always + + #podAnnotations: {} + + service: + name: jhipster-registry-service + type: ClusterIP + port: 8761 + + resources: + requests: + memory: "512Mi" + cpu: "1000m" + limits: + memory: "1024Mi" + cpu: "2000m" + +broker: + image: + repository: "ghcr.io/ls1intum/" + name: "activemq-broker-docker-adoptopenjdk-11" + version: "2.21.0" + pullPolicy: Always + + service: + name: "activemq-broker" + type: ClusterIP + port: 61616 + + resources: + requests: + memory: "512Mi" + cpu: "1000m" + limits: + memory: "1024Mi" + cpu: "2000m" + +# Prometheus server & adapter for horizontal autoscaling +prometheus: + alertmanager: + enabled: false + kubeStateMetrics: + enabled: false + nodeExporter: + enabled: false + pushgateway: + enabled: false + server: + global: + scrape_interval: "15s" + +prometheus-adapter: + rbac: + # Whether e.g. a ClusterRoleBinding should be created. This should usually be set to false if artemis.autoscaaler.customPrometheus is set to true. + create: true + rules: + # You might want to disable the default roles in case you use a custom prometheus instance + default: true + external: + # This rule transforms the metrics provided by Artemis (Prometheus-metrics) to Kubernetes metrics. The labels are also transformed. + - seriesQuery: '{range!=""}' + resources: + template: <<.Resource>> + metricsQuery: avg(<<.Series>>{<<.LabelMatchers>>}) + prometheus: + port: 80 + url: http://{{ tpl (.Release.Name) . }}-prometheus-server.{{ tpl (.Release.Namespace) . }}.svc +# End Prometheus server & adapter for horizontal autoscaling