{{- if (or (and (ne (.Values.server.enabled | toString) "-") .Values.server.enabled) (and (eq (.Values.server.enabled | toString) "-") .Values.global.enabled)) }} {{- if and .Values.global.federation.enabled .Values.global.adminPartitions.enabled }}{{ fail "If global.federation.enabled is true, global.adminPartitions.enabled must be false because they are mutually exclusive" }}{{ end }} {{- if and .Values.global.federation.enabled (not .Values.global.tls.enabled) }}{{ fail "If global.federation.enabled is true, global.tls.enabled must be true because federation is only supported with TLS enabled" }}{{ end }} {{- if and .Values.global.federation.enabled (not .Values.meshGateway.enabled) }}{{ fail "If global.federation.enabled is true, meshGateway.enabled must be true because mesh gateways are required for federation" }}{{ end }} {{- if and .Values.server.serverCert.secretName (not .Values.global.tls.caCert.secretName) }}{{ fail "If server.serverCert.secretName is provided, global.tls.caCert must also be provided" }}{{ end }} {{- if .Values.server.disableFsGroupSecurityContext }}{{ fail "server.disableFsGroupSecurityContext has been removed. Please use global.openshift.enabled instead." }}{{ end }} {{- if .Values.server.bootstrapExpect }}{{ if lt (int .Values.server.bootstrapExpect) (int .Values.server.replicas) }}{{ fail "server.bootstrapExpect cannot be less than server.replicas" }}{{ end }}{{ end }} {{- if (and .Values.global.gossipEncryption.secretName (not .Values.global.gossipEncryption.secretKey)) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and (not .Values.global.gossipEncryption.secretName) .Values.global.gossipEncryption.secretKey) }}{{fail "gossipEncryption.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and .Values.global.secretsBackend.vault.enabled (not .Values.global.secretsBackend.vault.consulServerRole)) }}{{ fail "global.secretsBackend.vault.consulServerRole must be provided if global.secretsBackend.vault.enabled=true." }}{{ end -}} {{- if (and .Values.server.serverCert.secretName (not .Values.global.tls.caCert.secretName)) }}{{ fail "If server.serverCert.secretName is provided, global.tls.caCert.secretName must also be provided" }}{{ end }} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.caCert.secretName)) }}{{ fail "global.tls.caCert.secretName must be provided if global.tls.enabled=true and global.secretsBackend.vault.enabled=true." }}{{ end -}} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.tls.enableAutoEncrypt)) }}{{ fail "global.tls.enableAutoEncrypt must be true if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} {{- if (and (and .Values.global.secretsBackend.vault.enabled .Values.global.tls.enabled) (not .Values.global.secretsBackend.vault.consulCARole)) }}{{ fail "global.secretsBackend.vault.consulCARole must be provided if global.secretsBackend.vault.enabled=true and global.tls.enabled=true" }}{{ end -}} {{- if (and .Values.global.enterpriseLicense.secretName (not .Values.global.enterpriseLicense.secretKey)) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and (not .Values.global.enterpriseLicense.secretName) .Values.global.enterpriseLicense.secretKey) }}{{fail "enterpriseLicense.secretKey and secretName must both be specified." }}{{ end -}} {{- if (and .Values.global.acls.bootstrapToken.secretName (not .Values.global.acls.bootstrapToken.secretKey)) }}{{fail "both global.acls.bootstrapToken.secretKey and global.acls.bootstrapToken.secretName must be set if one of them is provided." }}{{ end -}} {{- if (and (not .Values.global.acls.bootstrapToken.secretName) .Values.global.acls.bootstrapToken.secretKey) }}{{fail "both global.acls.bootstrapToken.secretKey and global.acls.bootstrapToken.secretName must be set if one of them is provided." }}{{ end -}} # StatefulSet to run the actual Consul server cluster. apiVersion: apps/v1 kind: StatefulSet metadata: name: {{ template "consul.fullname" . }}-server namespace: {{ .Release.Namespace }} labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} heritage: {{ .Release.Service }} release: {{ .Release.Name }} component: server spec: serviceName: {{ template "consul.fullname" . }}-server podManagementPolicy: Parallel replicas: {{ .Values.server.replicas }} {{- if (gt (int .Values.server.updatePartition) 0) }} updateStrategy: type: RollingUpdate rollingUpdate: partition: {{ .Values.server.updatePartition }} {{- end }} selector: matchLabels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} release: {{ .Release.Name }} component: server hasDNS: "true" template: metadata: labels: app: {{ template "consul.name" . }} chart: {{ template "consul.chart" . }} release: {{ .Release.Name }} component: server hasDNS: "true" {{- if .Values.server.extraLabels }} {{- toYaml .Values.server.extraLabels | nindent 8 }} {{- end }} annotations: {{- if .Values.global.secretsBackend.vault.enabled }} "vault.hashicorp.com/agent-inject": "true" "vault.hashicorp.com/role": "{{ .Values.global.secretsBackend.vault.consulServerRole }}" {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} "vault.hashicorp.com/agent-extra-secret": {{ .Values.global.secretsBackend.vault.ca.secretName }} "vault.hashicorp.com/ca-cert": /vault/custom/{{ .Values.global.secretsBackend.vault.ca.secretKey }} {{- end }} {{- if .Values.global.gossipEncryption.secretName }} {{- with .Values.global.gossipEncryption }} "vault.hashicorp.com/agent-inject-secret-gossip.txt": "{{ .secretName }}" "vault.hashicorp.com/agent-inject-template-gossip.txt": {{ template "consul.vaultSecretTemplate" . }} {{- end }} {{- end }} {{- if .Values.server.serverCert.secretName }} "vault.hashicorp.com/agent-inject-secret-servercert.crt": {{ .Values.server.serverCert.secretName }} "vault.hashicorp.com/agent-inject-template-servercert.crt": {{ include "consul.serverTLSCertTemplate" . }} "vault.hashicorp.com/agent-inject-secret-servercert.key": {{ .Values.server.serverCert.secretName }} "vault.hashicorp.com/agent-inject-template-servercert.key": {{ include "consul.serverTLSKeyTemplate" . }} "vault.hashicorp.com/agent-inject-secret-serverca.crt": {{ .Values.global.tls.caCert.secretName }} "vault.hashicorp.com/agent-inject-template-serverca.crt": {{ include "consul.serverTLSCATemplate" . }} {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName (not .Values.global.acls.createReplicationToken)) }} "vault.hashicorp.com/agent-inject-secret-replication-token-config.hcl": "{{ .Values.global.acls.replicationToken.secretName }}" "vault.hashicorp.com/agent-inject-template-replication-token-config.hcl": {{ template "consul.vaultReplicationTokenConfigTemplate" . }} {{- end }} {{- if (and .Values.global.acls.manageSystemACLs .Values.global.acls.bootstrapToken.secretName) }} "vault.hashicorp.com/agent-inject-secret-bootstrap-token-config.hcl": "{{ .Values.global.acls.bootstrapToken.secretName }}" "vault.hashicorp.com/agent-inject-template-bootstrap-token-config.hcl": {{ template "consul.vaultBootstrapTokenConfigTemplate" . }} {{- end }} {{- if .Values.global.secretsBackend.vault.agentAnnotations }} {{ tpl .Values.global.secretsBackend.vault.agentAnnotations . | nindent 8 | trim }} {{- end }} {{- if .Values.global.enterpriseLicense.secretName }} {{- with .Values.global.enterpriseLicense }} "vault.hashicorp.com/agent-inject-secret-enterpriselicense.txt": "{{ .secretName }}" "vault.hashicorp.com/agent-inject-template-enterpriselicense.txt": {{ template "consul.vaultSecretTemplate" . }} {{- end }} {{- end }} {{- end }} "consul.hashicorp.com/connect-inject": "false" "consul.hashicorp.com/config-checksum": {{ include (print $.Template.BasePath "/server-config-configmap.yaml") . | sha256sum }} {{- if .Values.server.annotations }} {{- tpl .Values.server.annotations . | nindent 8 }} {{- end }} {{- if (and .Values.global.metrics.enabled .Values.global.metrics.enableAgentMetrics) }} "prometheus.io/scrape": "true" "prometheus.io/path": "/v1/agent/metrics" "prometheus.io/port": "8500" {{- end }} spec: {{- if .Values.server.affinity }} affinity: {{ tpl .Values.server.affinity . | nindent 8 | trim }} {{- end }} {{- if .Values.server.tolerations }} tolerations: {{ tpl .Values.server.tolerations . | nindent 8 | trim }} {{- end }} {{- if .Values.server.topologySpreadConstraints }} topologySpreadConstraints: {{ tpl .Values.server.topologySpreadConstraints . | nindent 8 | trim }} {{- end }} terminationGracePeriodSeconds: 30 serviceAccountName: {{ template "consul.fullname" . }}-server {{- if not .Values.global.openshift.enabled }} securityContext: {{- toYaml .Values.server.securityContext | nindent 8 }} {{- end }} volumes: - name: config configMap: name: {{ template "consul.fullname" . }}-server-config - name: extra-config emptyDir: {} {{- if (and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-ca-cert secret: {{- if .Values.global.tls.caCert.secretName }} secretName: {{ .Values.global.tls.caCert.secretName }} {{- else }} secretName: {{ template "consul.fullname" . }}-ca-cert {{- end }} items: - key: {{ default "tls.crt" .Values.global.tls.caCert.secretKey }} path: tls.crt - name: consul-server-cert secret: {{- if .Values.server.serverCert.secretName }} secretName: {{ .Values.server.serverCert.secretName }} {{- else }} secretName: {{ template "consul.fullname" . }}-server-cert {{- end }} {{- end }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license secret: secretName: {{ .Values.global.enterpriseLicense.secretName }} {{- end }} {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} - name: vault-ca secret: secretName: {{ .Values.global.secretsBackend.vault.ca.secretName }} items: - key: {{ .Values.global.secretsBackend.vault.ca.secretKey }} path: tls.crt {{- end }} {{- range .Values.server.extraVolumes }} - name: userconfig-{{ .name }} {{ .type }}: {{- if (eq .type "configMap") }} name: {{ .name }} {{- else if (eq .type "secret") }} secretName: {{ .name }} {{- end }} {{- with .items }} items: {{- range . }} - key: {{.key}} path: {{.path}} {{- end }} {{- end }} {{- end }} {{- if .Values.server.priorityClassName }} priorityClassName: {{ .Values.server.priorityClassName | quote }} {{- end }} containers: - name: consul image: "{{ default .Values.global.image .Values.server.image }}" env: - name: ADVERTISE_IP valueFrom: fieldRef: {{- if .Values.server.exposeGossipAndRPCPorts }} {{- /* Server gossip and RPC ports will be exposed as a hostPort on the hostIP, so they need to advertise their host ip instead of their pod ip. This is to support external client agents. */}} fieldPath: status.hostIP {{- else }} fieldPath: status.podIP {{- end }} - name: HOST_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: POD_IP valueFrom: fieldRef: fieldPath: status.podIP - name: CONSUL_DISABLE_PERM_MGMT value: "true" {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} {{- if not .Values.global.secretsBackend.vault.enabled }} - name: GOSSIP_KEY valueFrom: secretKeyRef: {{- if .Values.global.gossipEncryption.autoGenerate }} name: {{ template "consul.fullname" . }}-gossip-encryption-key key: key {{- else if (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey) }} name: {{ .Values.global.gossipEncryption.secretName }} key: {{ .Values.global.gossipEncryption.secretKey }} {{- end }} {{- end }} {{- end }} {{- if .Values.global.tls.enabled }} - name: CONSUL_HTTP_ADDR value: https://localhost:8501 - name: CONSUL_CACERT {{- if .Values.global.secretsBackend.vault.enabled }} value: /vault/secrets/serverca.crt {{- else }} value: /consul/tls/ca/tls.crt {{- end }} {{- end }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload) }} - name: CONSUL_LICENSE_PATH {{- if .Values.global.secretsBackend.vault.enabled }} value: /vault/secrets/enterpriselicense.txt {{- else }} value: /consul/license/{{ .Values.global.enterpriseLicense.secretKey }} {{- end }} {{- end }} {{- if and (not .Values.global.secretsBackend.vault.enabled) .Values.global.acls.bootstrapToken.secretName }} - name: ACL_BOOTSTRAP_TOKEN valueFrom: secretKeyRef: name: {{ .Values.global.acls.bootstrapToken.secretName | quote }} key: {{ .Values.global.acls.bootstrapToken.secretKey | quote }} {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey (not .Values.global.secretsBackend.vault.enabled)) }} - name: ACL_REPLICATION_TOKEN valueFrom: secretKeyRef: name: {{ .Values.global.acls.replicationToken.secretName | quote }} key: {{ .Values.global.acls.replicationToken.secretKey | quote }} {{- end }} {{- include "consul.extraEnvironmentVars" .Values.server | nindent 12 }} command: - "/bin/sh" - "-ec" - | {{- if and .Values.global.secretsBackend.vault.enabled .Values.global.gossipEncryption.secretName }} GOSSIP_KEY=`cat /vault/secrets/gossip.txt` {{- end }} {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} {{ template "consul.recursors" }} {{- end }} {{ template "consul.extraconfig" }} exec /usr/local/bin/docker-entrypoint.sh consul agent \ -advertise="${ADVERTISE_IP}" \ -config-dir=/consul/config \ {{- if (or .Values.global.gossipEncryption.autoGenerate (and .Values.global.gossipEncryption.secretName .Values.global.gossipEncryption.secretKey)) }} -encrypt="${GOSSIP_KEY}" \ {{- end }} {{- if (and .Values.global.acls.replicationToken.secretName .Values.global.acls.replicationToken.secretKey) }} {{- if (and .Values.global.secretsBackend.vault.enabled (not .Values.global.acls.createReplicationToken)) }} -config-file=/vault/secrets/replication-token-config.hcl \ {{- else }} -hcl="acl { tokens { agent = \"${ACL_REPLICATION_TOKEN}\", replication = \"${ACL_REPLICATION_TOKEN}\" } }" \ {{- end }} {{- end }} {{- if (and .Values.dns.enabled .Values.dns.enableRedirection) }} $recursor_flags \ {{- end }} {{- if and .Values.global.secretsBackend.vault.enabled .Values.global.acls.bootstrapToken.secretName }} -config-file=/vault/secrets/bootstrap-token-config.hcl \ {{- else if (and (not .Values.global.secretsBackend.vault.enabled) .Values.global.acls.bootstrapToken.secretName) }} -hcl="acl { tokens { initial_management = \"${ACL_BOOTSTRAP_TOKEN}\" } }" \ {{- end }} {{- /* Always include the extraVolumes at the end so that users can override other Consul settings. The last -config-dir takes precedence. */}} {{- range .Values.server.extraVolumes }} {{- if .load }} -config-dir=/consul/userconfig/{{ .name }} \ {{- end }} {{- end }} -config-file=/consul/extra-config/extra-from-values.json volumeMounts: - name: data-{{ .Release.Namespace | trunc 58 | trimSuffix "-" }} mountPath: /consul/data - name: config mountPath: /consul/config - name: extra-config mountPath: /consul/extra-config {{- if (and .Values.global.tls.enabled (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-ca-cert mountPath: /consul/tls/ca/ readOnly: true - name: consul-server-cert mountPath: /consul/tls/server readOnly: true {{- end }} {{- if (and .Values.global.enterpriseLicense.secretName .Values.global.enterpriseLicense.enableLicenseAutoload (not .Values.global.secretsBackend.vault.enabled)) }} - name: consul-license mountPath: /consul/license readOnly: true {{- end }} {{- range .Values.server.extraVolumes }} - name: userconfig-{{ .name }} readOnly: true mountPath: /consul/userconfig/{{ .name }} {{- end }} {{- if and .Values.global.secretsBackend.vault.ca.secretName .Values.global.secretsBackend.vault.ca.secretKey }} - name: vault-ca mountPath: /consul/vault-ca/ readOnly: true {{- end }} ports: {{- if (or (not .Values.global.tls.enabled) (not .Values.global.tls.httpsOnly)) }} - name: http containerPort: 8500 {{- end }} {{- if .Values.global.tls.enabled }} - name: https containerPort: 8501 {{- end }} - containerPort: 8503 {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: 8503 {{- end }} name: grpc - name: serflan-tcp containerPort: {{ .Values.server.ports.serflan.port }} {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: {{ .Values.server.ports.serflan.port }} {{- end }} protocol: "TCP" - name: serflan-udp containerPort: {{ .Values.server.ports.serflan.port }} {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: {{ .Values.server.ports.serflan.port }} {{- end }} protocol: "UDP" - name: serfwan-tcp containerPort: 8302 {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: 8302 {{- end }} protocol: "TCP" - name: serfwan-udp containerPort: 8302 {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: 8302 {{- end }} protocol: "UDP" - name: server containerPort: 8300 {{- if .Values.server.exposeGossipAndRPCPorts }} hostPort: 8300 {{- end }} - name: dns-tcp containerPort: 8600 protocol: "TCP" - name: dns-udp containerPort: 8600 protocol: "UDP" readinessProbe: # NOTE(mitchellh): when our HTTP status endpoints support the # proper status codes, we should switch to that. This is temporary. exec: command: - "/bin/sh" - "-ec" - | {{- if .Values.global.tls.enabled }} curl -k \ https://127.0.0.1:8501/v1/status/leader \ {{- else }} curl http://127.0.0.1:8500/v1/status/leader \ {{- end }} 2>/dev/null | grep -E '".+"' failureThreshold: 2 initialDelaySeconds: 5 periodSeconds: 3 successThreshold: 1 timeoutSeconds: 5 {{- if .Values.server.resources }} resources: {{- if eq (typeOf .Values.server.resources) "string" }} {{ tpl .Values.server.resources . | nindent 12 | trim }} {{- else }} {{- toYaml .Values.server.resources | nindent 12 }} {{- end }} {{- end }} {{- if not .Values.global.openshift.enabled }} securityContext: {{- toYaml .Values.server.containerSecurityContext.server | nindent 12 }} {{- end }} {{- if .Values.server.extraContainers }} {{ toYaml .Values.server.extraContainers | nindent 8 }} {{- end }} {{- if .Values.server.nodeSelector }} nodeSelector: {{ tpl .Values.server.nodeSelector . | indent 8 | trim }} {{- end }} volumeClaimTemplates: - metadata: name: data-{{ .Release.Namespace | trunc 58 | trimSuffix "-" }} spec: accessModes: - ReadWriteOnce resources: requests: storage: {{ .Values.server.storage }} {{- if .Values.server.storageClass }} storageClassName: {{ .Values.server.storageClass }} {{- end }} {{- end }}