You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2021/03/03 20:23:44 UTC
[lucene-solr-operator] branch main updated: Add
terminationGracePeriod option, and use it when killing Solr pods. (#226)
This is an automated email from the ASF dual-hosted git repository.
houston pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/lucene-solr-operator.git
The following commit(s) were added to refs/heads/main by this push:
new 497630e Add terminationGracePeriod option, and use it when killing Solr pods. (#226)
497630e is described below
commit 497630e089896ba60701285fd55a02d05a5ff93c
Author: Houston Putman <ho...@apache.org>
AuthorDate: Wed Mar 3 15:23:40 2021 -0500
Add terminationGracePeriod option, and use it when killing Solr pods. (#226)
terminationGracePeriod used to be statically set to 10 seconds. Now it defaults to 30 seconds, but is configurable.
SOLR_STOP_WAIT will be set to the terminationGracePeriod, minus a few seconds, so that kubernetes and Solr are on the same page.
---
api/v1beta1/common_types.go | 5 ++
api/v1beta1/zz_generated.deepcopy.go | 5 ++
config/crd/bases/solr.apache.org_solrclouds.yaml | 5 ++
.../solr.apache.org_solrprometheusexporters.yaml | 5 ++
controllers/controller_utils_test.go | 3 +-
controllers/solrcloud_controller_test.go | 22 +++---
.../solrprometheusexporter_controller_test.go | 18 +++--
controllers/util/common.go | 6 ++
controllers/util/prometheus_exporter_util.go | 4 +
controllers/util/solr_util.go | 18 ++++-
docs/solr-cloud/solr-cloud-crd.md | 92 ++++++++++++++--------
helm/solr-operator/crds/crds.yaml | 10 +++
12 files changed, 138 insertions(+), 55 deletions(-)
diff --git a/api/v1beta1/common_types.go b/api/v1beta1/common_types.go
index 053d262..34133f4 100644
--- a/api/v1beta1/common_types.go
+++ b/api/v1beta1/common_types.go
@@ -124,6 +124,11 @@ type PodOptions struct {
// solr image.
// +optional
ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"`
+
+ // Optional duration in seconds the pod needs to terminate gracefully.
+ // +kubebuilder:validation:Minimum=10
+ // +optional
+ TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"`
}
// ServiceOptions defines custom options for services
diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go
index 86847d9..6810efe 100644
--- a/api/v1beta1/zz_generated.deepcopy.go
+++ b/api/v1beta1/zz_generated.deepcopy.go
@@ -469,6 +469,11 @@ func (in *PodOptions) DeepCopyInto(out *PodOptions) {
*out = make([]v1.LocalObjectReference, len(*in))
copy(*out, *in)
}
+ if in.TerminationGracePeriodSeconds != nil {
+ in, out := &in.TerminationGracePeriodSeconds, &out.TerminationGracePeriodSeconds
+ *out = new(int64)
+ **out = **in
+ }
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodOptions.
diff --git a/config/crd/bases/solr.apache.org_solrclouds.yaml b/config/crd/bases/solr.apache.org_solrclouds.yaml
index 47bede4..1355e2e 100644
--- a/config/crd/bases/solr.apache.org_solrclouds.yaml
+++ b/config/crd/bases/solr.apache.org_solrclouds.yaml
@@ -2417,6 +2417,11 @@ spec:
format: int32
type: integer
type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs to terminate gracefully.
+ format: int64
+ minimum: 10
+ type: integer
tolerations:
description: Tolerations to be added for the StatefulSet.
items:
diff --git a/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml b/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
index 16288ed..73ae207 100644
--- a/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
+++ b/config/crd/bases/solr.apache.org_solrprometheusexporters.yaml
@@ -2346,6 +2346,11 @@ spec:
format: int32
type: integer
type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs to terminate gracefully.
+ format: int64
+ minimum: 10
+ type: integer
tolerations:
description: Tolerations to be added for the StatefulSet.
items:
diff --git a/controllers/controller_utils_test.go b/controllers/controller_utils_test.go
index e3565d4..8e9b3a7 100644
--- a/controllers/controller_utils_test.go
+++ b/controllers/controller_utils_test.go
@@ -543,7 +543,8 @@ var (
{Name: "ADDITIONAL_SECRET_1"},
{Name: "ADDITIONAL_SECRET_2"},
}
- extraVars = []corev1.EnvVar{
+ testTerminationGracePeriodSeconds = int64(50)
+ extraVars = []corev1.EnvVar{
{
Name: "VAR_1",
Value: "VAL_1",
diff --git a/controllers/solrcloud_controller_test.go b/controllers/solrcloud_controller_test.go
index 340b5a3..a047b8e 100644
--- a/controllers/solrcloud_controller_test.go
+++ b/controllers/solrcloud_controller_test.go
@@ -20,6 +20,7 @@ package controllers
import (
"crypto/md5"
"fmt"
+ "strconv"
"time"
solr "github.com/apache/lucene-solr-operator/api/v1beta1"
@@ -189,15 +190,16 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
SolrGCTune: "gc Options",
CustomSolrKubeOptions: solr.CustomSolrKubeOptions{
PodOptions: &solr.PodOptions{
- Annotations: testPodAnnotations,
- Labels: testPodLabels,
- Tolerations: testTolerations,
- NodeSelector: testNodeSelectors,
- LivenessProbe: testProbeLivenessNonDefaults,
- ReadinessProbe: testProbeReadinessNonDefaults,
- StartupProbe: testProbeStartup,
- PriorityClassName: testPriorityClass,
- ImagePullSecrets: testAdditionalImagePullSecrets,
+ Annotations: testPodAnnotations,
+ Labels: testPodLabels,
+ Tolerations: testTolerations,
+ NodeSelector: testNodeSelectors,
+ LivenessProbe: testProbeLivenessNonDefaults,
+ ReadinessProbe: testProbeReadinessNonDefaults,
+ StartupProbe: testProbeStartup,
+ PriorityClassName: testPriorityClass,
+ ImagePullSecrets: testAdditionalImagePullSecrets,
+ TerminationGracePeriodSeconds: &testTerminationGracePeriodSeconds,
},
StatefulSetOptions: &solr.StatefulSetOptions{
Annotations: testSSAnnotations,
@@ -268,6 +270,7 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
"SOLR_NODE_PORT": "8983",
"GC_TUNE": "gc Options",
"SOLR_OPTS": "-DhostPort=$(SOLR_NODE_PORT)",
+ "SOLR_STOP_WAIT": strconv.FormatInt(testTerminationGracePeriodSeconds-5, 10),
}
expectedStatefulSetLabels := util.MergeLabelsOrAnnotations(instance.SharedLabelsWith(instance.Labels), map[string]string{"technology": "solr-cloud"})
expectedStatefulSetAnnotations := map[string]string{util.SolrZKConnectionStringAnnotation: "host:7271/"}
@@ -283,6 +286,7 @@ func TestCustomKubeOptionsCloudReconcile(t *testing.T) {
testPodTolerations(t, testTolerations, statefulSet.Spec.Template.Spec.Tolerations)
assert.EqualValues(t, testPriorityClass, statefulSet.Spec.Template.Spec.PriorityClassName, "Incorrect Priority class name for Pod Spec")
assert.ElementsMatch(t, append(testAdditionalImagePullSecrets, corev1.LocalObjectReference{Name: testImagePullSecretName}), statefulSet.Spec.Template.Spec.ImagePullSecrets, "Incorrect imagePullSecrets")
+ assert.EqualValues(t, &testTerminationGracePeriodSeconds, statefulSet.Spec.Template.Spec.TerminationGracePeriodSeconds, "Incorrect terminationGracePeriodSeconds")
// Check the update strategy
assert.EqualValues(t, appsv1.RollingUpdateStatefulSetStrategyType, statefulSet.Spec.UpdateStrategy.Type, "Incorrect statefulset update strategy")
diff --git a/controllers/solrprometheusexporter_controller_test.go b/controllers/solrprometheusexporter_controller_test.go
index 3e72e43..523e5f0 100644
--- a/controllers/solrprometheusexporter_controller_test.go
+++ b/controllers/solrprometheusexporter_controller_test.go
@@ -56,14 +56,15 @@ func TestMetricsReconcileWithoutExporterConfig(t *testing.T) {
Spec: solr.SolrPrometheusExporterSpec{
CustomKubeOptions: solr.CustomExporterKubeOptions{
PodOptions: &solr.PodOptions{
- EnvVariables: extraVars,
- PodSecurityContext: &podSecurityContext,
- Volumes: extraVolumes,
- Affinity: affinity,
- Resources: resources,
- SidecarContainers: extraContainers2,
- InitContainers: extraContainers1,
- ImagePullSecrets: testAdditionalImagePullSecrets,
+ EnvVariables: extraVars,
+ PodSecurityContext: &podSecurityContext,
+ Volumes: extraVolumes,
+ Affinity: affinity,
+ Resources: resources,
+ SidecarContainers: extraContainers2,
+ InitContainers: extraContainers1,
+ ImagePullSecrets: testAdditionalImagePullSecrets,
+ TerminationGracePeriodSeconds: &testTerminationGracePeriodSeconds,
},
},
ExporterEntrypoint: "/test/entry-point",
@@ -129,6 +130,7 @@ func TestMetricsReconcileWithoutExporterConfig(t *testing.T) {
assert.Equal(t, extraVolumes[0].Name, deployment.Spec.Template.Spec.Volumes[0].Name, "Additional Volume from podOptions not loaded into pod properly.")
assert.Equal(t, extraVolumes[0].Source, deployment.Spec.Template.Spec.Volumes[0].VolumeSource, "Additional Volume from podOptions not loaded into pod properly.")
assert.ElementsMatch(t, append(testAdditionalImagePullSecrets, corev1.LocalObjectReference{Name: testImagePullSecretName}), deployment.Spec.Template.Spec.ImagePullSecrets, "Incorrect imagePullSecrets")
+ assert.EqualValues(t, &testTerminationGracePeriodSeconds, deployment.Spec.Template.Spec.TerminationGracePeriodSeconds, "Incorrect terminationGracePeriodSeconds")
service := expectService(t, g, requests, expectedMetricsRequest, metricsSKey, deployment.Spec.Template.Labels)
assert.Equal(t, "true", service.Annotations["prometheus.io/scrape"], "Metrics Service Prometheus scraping is not enabled.")
diff --git a/controllers/util/common.go b/controllers/util/common.go
index 5b57101..7d4cf1b 100644
--- a/controllers/util/common.go
+++ b/controllers/util/common.go
@@ -422,6 +422,12 @@ func CopyPodTemplates(from, to *corev1.PodTemplateSpec, basePath string, logger
to.Spec.PriorityClassName = from.Spec.PriorityClassName
}
+ if !DeepEqualWithNils(to.Spec.TerminationGracePeriodSeconds, from.Spec.TerminationGracePeriodSeconds) {
+ requireUpdate = true
+ logger.Info("Update required because field changed", "field", basePath+"Spec.TerminationGracePeriodSeconds", "from", to.Spec.TerminationGracePeriodSeconds, "to", from.Spec.TerminationGracePeriodSeconds)
+ to.Spec.TerminationGracePeriodSeconds = from.Spec.TerminationGracePeriodSeconds
+ }
+
return requireUpdate
}
diff --git a/controllers/util/prometheus_exporter_util.go b/controllers/util/prometheus_exporter_util.go
index 6496d43..88e7653 100644
--- a/controllers/util/prometheus_exporter_util.go
+++ b/controllers/util/prometheus_exporter_util.go
@@ -330,6 +330,10 @@ func GenerateSolrPrometheusExporterDeployment(solrPrometheusExporter *solr.SolrP
if customPodOptions.PriorityClassName != "" {
deployment.Spec.Template.Spec.PriorityClassName = customPodOptions.PriorityClassName
}
+
+ if customPodOptions.TerminationGracePeriodSeconds != nil {
+ deployment.Spec.Template.Spec.TerminationGracePeriodSeconds = customPodOptions.TerminationGracePeriodSeconds
+ }
}
return deployment
diff --git a/controllers/util/solr_util.go b/controllers/util/solr_util.go
index 873f49c..0c5b542 100644
--- a/controllers/util/solr_util.go
+++ b/controllers/util/solr_util.go
@@ -92,7 +92,7 @@ const (
// storage: the size of the storage for the SolrCloud instance (e.g. 100Gi)
// zkConnectionString: the connectionString of the ZK instance to connect to
func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCloudStatus, hostNameIPs map[string]string, reconcileConfigInfo map[string]string, createPkcs12InitContainer bool, tlsCertMd5 string) *appsv1.StatefulSet {
- gracePeriodTerm := int64(10)
+ terminationGracePeriod := int64(60)
solrPodPort := solrCloud.Spec.SolrAddressability.PodPort
fsGroup := int64(DefaultSolrGroup)
defaultMode := int32(420)
@@ -133,6 +133,10 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCl
if nil != customPodOptions {
podLabels = MergeLabelsOrAnnotations(podLabels, customPodOptions.Labels)
podAnnotations = customPodOptions.Annotations
+
+ if customPodOptions.TerminationGracePeriodSeconds != nil {
+ terminationGracePeriod = *customPodOptions.TerminationGracePeriodSeconds
+ }
}
// Keep track of the SolrOpts that the Solr Operator needs to set
@@ -274,6 +278,12 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCl
solrHostName := solrCloud.AdvertisedNodeHost("$(POD_HOSTNAME)")
solrAdressingPort := solrCloud.NodePort()
+ // Solr can take longer than SOLR_STOP_WAIT to run solr stop, give it a few extra seconds before forcefully killing the pod.
+ solrStopWait := terminationGracePeriod - 5
+ if solrStopWait < 0 {
+ solrStopWait = 0
+ }
+
// Environment Variables
envVars := []corev1.EnvVar{
{
@@ -315,6 +325,10 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCl
Name: "GC_TUNE",
Value: solrCloud.Spec.SolrGCTune,
},
+ {
+ Name: "SOLR_STOP_WAIT",
+ Value: strconv.FormatInt(solrStopWait, 10),
+ },
}
// Add all necessary information for connection to Zookeeper
@@ -530,7 +544,7 @@ func GenerateStatefulSet(solrCloud *solr.SolrCloud, solrCloudStatus *solr.SolrCl
},
Spec: corev1.PodSpec{
- TerminationGracePeriodSeconds: &gracePeriodTerm,
+ TerminationGracePeriodSeconds: &terminationGracePeriod,
SecurityContext: &corev1.PodSecurityContext{
FSGroup: &fsGroup,
},
diff --git a/docs/solr-cloud/solr-cloud-crd.md b/docs/solr-cloud/solr-cloud-crd.md
index 13fe812..8fd20b2 100644
--- a/docs/solr-cloud/solr-cloud-crd.md
+++ b/docs/solr-cloud/solr-cloud-crd.md
@@ -146,7 +146,7 @@ However, there may come a time when you need to override the built-in configurat
In general, users can provide custom config files by providing a ConfigMap in the same namespace as the SolrCloud instance;
all custom config files should be stored in the same user-provided ConfigMap under different keys.
Point your SolrCloud definition to a user-provided ConfigMap using the following structure:
-```
+```yaml
spec:
...
customSolrKubeOptions:
@@ -163,13 +163,13 @@ The default `solr.xml` is mounted into the `cp-solr-xml` initContainer from a Co
_Note: The data in the default ConfigMap is not editable! Any changes to the `solr.xml` in the default ConfigMap created by the operator will be overwritten during the next reconcile cycle._
Many of the specific values in `solr.xml` can be set using Java system properties; for instance, the following setting controls the read timeout for the HTTP client used by Solr's `HttpShardHandlerFactory`:
-```
+```xml
<int name="socketTimeout">${socketTimeout:600000}</int>
```
The `${socketTimeout:600000}` syntax means pull the value from a Java system property named `socketTimeout` with default `600000` if not set.
You can set Java system properties using the `solrOpts` string in your SolrCloud definition, such as:
-```
+```yaml
spec:
solrOpts: -DsocketTimeout=300000
```
@@ -178,7 +178,7 @@ This same approach works for a number of settings in `solrconfig.xml` as well.
However, if you need to customize `solr.xml` beyond what can be accomplished with Java system properties,
then you need to supply your own `solr.xml` in a ConfigMap in the same namespace where you deploy your SolrCloud instance.
Provide your custom XML in the ConfigMap using `solr.xml` as the key as shown in the example below:
-```
+```yaml
---
kind: ConfigMap
apiVersion: v1
@@ -194,7 +194,7 @@ data:
**Important: Your custom `solr.xml` must include `<int name="hostPort">${hostPort:0}</int>` as the operator relies on this element to set the port Solr pods advertise to ZooKeeper. If this element is missing, then your Solr pods will not be created.**
You can get the default `solr.xml` from a Solr pod as a starting point for creating a custom config using `kubectl cp` as shown in the example below:
-```
+```bash
SOLR_POD_ID=$(kubectl get pod -l technology=solr-cloud --no-headers -o custom-columns=":metadata.name" | head -1)
kubectl cp $SOLR_POD_ID:/var/solr/data/solr.xml ./custom-solr.xml
```
@@ -203,7 +203,8 @@ This copies the default config from the first Solr pod found in the namespace an
_Note: Using `kubectl create configmap --from-file` scrambles the XML formatting, so we recommend defining the configmap YAML as shown above to keep the XML formatted properly._
Point your SolrCloud instance at the custom ConfigMap using:
-```
+```yaml
+spec:
customSolrKubeOptions:
configMapOptions:
providedConfigMap: custom-solr-xml
@@ -213,7 +214,7 @@ _Note: If you set `providedConfigMap`, then the ConfigMap must include the `solr
#### Changes to Custom Config Trigger Rolling Restarts
The Solr operator stores the MD5 hash of your custom XML in the StatefulSet's pod spec annotations (`spec.template.metadata.annotations`). To see the current annotations for your Solr pods, you can do:
-```
+```bash
kubectl annotate pod -l technology=solr-cloud --list=true
```
If the custom `solr.xml` changes in the user-provided ConfigMap, then the operator triggers a rolling restart of Solr pods to apply the updated configuration settings automatically.
@@ -231,7 +232,7 @@ If your custom log config has a `monitorInterval` set, then the operator does no
Kubernetes will automatically update the file on each pod's filesystem when the data in the ConfigMap changes. Once Kubernetes updates the file, Log4j will pick up the changes and apply them without restarting the Solr pod.
If you need to customize both `solr.xml` and `log4j2.xml` then you need to supply both in the same ConfigMap using multiple keys as shown below:
-```
+```yaml
---
kind: ConfigMap
apiVersion: v1
@@ -274,7 +275,7 @@ If you do not have a TLS certificate, then we recommend installing **cert-manage
#### Install cert-manager
Given its popularity, cert-manager may already be installed in your Kubernetes cluster. To check if `cert-manager` is already installed, do:
-```
+```bash
kubectl get crds -l app.kubernetes.io/instance=cert-manager
```
If installed, you should see the following cert-manager related CRDs:
@@ -288,7 +289,7 @@ orders.acme.cert-manager.io
```
If not intalled, use Helm to install it into the `cert-manager` namespace:
-```
+```bash
if ! helm repo list | grep -q "https://charts.jetstack.io"; then
helm repo add jetstack https://charts.jetstack.io
helm repo update
@@ -311,13 +312,14 @@ Refer to the [cert-manager docs](https://cert-manager.io/docs/) on how to define
Certificate Issuers are typically platform specific. For instance, on GKE, to create a Let’s Encrypt Issuer you need a service account with various cloud DNS permissions granted for DNS01 challenges to work, see: https://cert-manager.io/docs/configuration/acme/dns01/google/.
The DNS names in your certificate should match the Solr addressability settings in your SolrCloud CRD. For instance, if your SolrCloud CRD uses the following settings:
-```
+```yaml
+spec:
solrAddressability:
external:
domainName: k8s.solr.cloud
```
Then your certificate needs the following domains specified:
-```
+```yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
@@ -335,7 +337,7 @@ will not generate a certificate for K8s internal DNS names (you'll get errors du
Another benefit is cert-manager can create a [PKCS12](https://cert-manager.io/docs/release-notes/release-notes-0.15/#general-availability-of-jks-and-pkcs-12-keystores) keystore automatically when issuing a `Certificate`,
which allows the Solr operator to mount the keystore directly on our Solr pods. Ensure your certificate instance requests **pkcs12 keystore** gets created using config similar to the following:
-```
+```yaml
keystores:
pkcs12:
create: true
@@ -358,7 +360,7 @@ Caused by: java.security.UnrecoverableKeyException: Get Key failed: null
Consequently, the Solr operator requires you to use a non-null password for your keystore.
Here's an example of how to use cert-manager to generate a self-signed certificate:
-```
+```yaml
---
apiVersion: v1
kind: Secret
@@ -399,7 +401,7 @@ spec:
```
Once created, simply point the SolrCloud deployment at the TLS and keystore password secrets, e.g.
-```
+```yaml
spec:
... other SolrCloud CRD settings ...
@@ -422,13 +424,13 @@ that contains a `tls.crt` file (x.509 certificate with a public key and info abo
Ideally, the TLS secret will also have a `pkcs12` keystore.
If the supplied TLS secret does not contain a `keystore.p12` key, then the Solr operator creates an `initContainer` on the StatefulSet to generate the keystore from the TLS secret using the following command:
-```
+```bash
openssl pkcs12 -export -in tls.crt -inkey tls.key -out keystore.p12 -passout pass:${SOLR_SSL_KEY_STORE_PASSWORD}"
```
_The `initContainer` uses the main Solr image as it has `openssl` installed._
Configure the SolrCloud deployment to point to the user-provided keystore and TLS secrets:
-```
+```yaml
spec:
... other SolrCloud CRD settings ...
@@ -444,7 +446,7 @@ spec:
### Ingress
The Solr operator may create an Ingress for exposing Solr pods externally. When TLS is enabled, the operator adds the following annotation and TLS settings to the Ingress manifest, such as:
-```
+```yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
@@ -469,7 +471,7 @@ However, the JVM only reads key and trust stores once during initialization and
The operator tracks the MD5 hash of the `tls.crt` from the TLS secret in an annotation on the StatefulSet pod spec so that when the TLS secret changes, it will trigger a rolling restart of the affected Solr pods.
The operator guards this behavior with an **opt-in** flag `restartOnTLSSecretUpdate` as some users may not want to restart Solr pods when the TLS secret holding the cert changes and may instead choose to restart the pods during a maintenance window (presumably before the certs expire).
-```
+```yaml
spec:
... other SolrCloud CRD settings ...
@@ -482,7 +484,7 @@ spec:
### Misc Config Settings for TLS Enabled Solr
Although not required, we recommend setting the `commonServicePort` and `nodePortOverride` to `443` instead of the default port `80` under `solrAddressability` to avoid confusion when working with `https`.
-```
+```yaml
spec:
... other SolrCloud CRD settings ...
@@ -497,7 +499,7 @@ spec:
If you're relying on a self-signed certificate (or any certificate that requires importing the CA into the Java trust store) for Solr pods, then the Prometheus Exporter will not be able to make requests for metrics.
You'll need to duplicate your TLS config from your SolrCloud CRD definition to your Prometheus exporter CRD definition as shown in the example below:
-```
+```yaml
solrReference:
cloud:
name: "dev"
@@ -526,7 +528,7 @@ Intuitively, this makes sense because services like LetsEncrypt cannot determine
Some CA's provide TLS certificates for private domains but that topic is beyond the scope of the Solr operator.
You may want to use a self-signed certificate for internal traffic and then a public certificate for your Ingress.
Alternatively, you can choose to expose Solr pods with an external name using SolrCloud `solrAddressability` settings:
-```
+```yaml
kind: SolrCloud
metadata:
name: search
@@ -567,7 +569,7 @@ With option 1, the operator creates the Basic Authentication Secret for you.
The easiest way to get started with Solr security is to have the operator bootstrap a `security.json` (stored in ZK) as part of the initial deployment process.
To activate this feature, add the following configuration to your SolrCloud CRD definition YAML:
-```
+```yaml
spec:
...
solrSecurity:
@@ -577,14 +579,14 @@ spec:
Once the cluster is up, you'll need the `admin` user password to login to the Solr Admin UI.
The `admin` user will have a random password generated by the operator during `security.json` bootstrapping.
Use the following command to retrieve the password from the bootstrap secret created by the operator:
-```
+```bash
kubectl get secret <CLOUD>-solrcloud-security-bootstrap -o jsonpath='{.data.admin}' | base64 --decode
```
_where `<CLOUD>` is the name of your SolrCloud_
Once `security.json` is bootstrapped, the operator will not update it! You're expected to use the `admin` user to access the Security API to make further changes.
In addition to the `admin` user, the operator defines a `solr` user, which has basic read access to Solr resources. You can retrieve the `solr` user password using:
-```
+```bash
kubectl get secret <CLOUD>-solrcloud-security-bootstrap -o jsonpath='{.data.solr}' | base64 --decode
```
@@ -602,7 +604,7 @@ Also, changing the password for the `k8s-oper` user in the K8s secret after boot
We recommend configuring Solr to allow un-authenticated access over HTTP to the probe endpoint(s) and the bootstrapped `security.json` does this for you automatically (see next sub-section).
However, if you want to secure the probe endpoints, then you need to set `probesRequireAuth: true` as shown below:
-```
+```yaml
spec:
...
solrSecurity:
@@ -618,7 +620,7 @@ If you customize the HTTP path for any probes (under `spec.customSolrKubeOptions
then you must use `probesRequireAuth=false` as the operator does not reconfigure custom HTTP probes to use the command needed to support `probesRequireAuth=true`.
If you're running Solr 8+, then we recommend using the `/admin/info/health` endpoint for your probes using the following config:
-```
+```yaml
spec:
...
customSolrKubeOptions:
@@ -635,13 +637,13 @@ spec:
port: 8983
```
Consequently, the bootstrapped `security.json` will include an additional rule to allow access to the `/admin/info/health` endpoint:
-```
+```json
{
"name": "k8s-probe-1",
"role": null,
"collection": null,
"path": "/admin/info/health"
- },
+ }
```
Note, if you change the probes after creating your solrcloud, then the new probe paths will not be added to the security.json.
@@ -652,7 +654,7 @@ The security file is bootstrapped just once, so if your probes need to change yo
The default `security.json` created by the operator during initialization is shown below; the passwords for each user are randomized for every SolrCloud you create.
In addition to configuring the `solr.BasicAuthPlugin`, the operator initializes a set of authorization rules for the default user accounts: `admin`, `solr`, and `k8s-oper`.
Take a moment to review these authorization rules so that you're aware of the roles and access granted to each user in your cluster.
-```
+```json
{
"authentication": {
"blockUnknown": false,
@@ -723,7 +725,7 @@ Take a moment to review these authorization rules so that you're aware of the ro
```
A few aspects of the default `security.json` configuration warrant a closer look. First, the `probesRequireAuth` setting
(defaults to `false`) governs the value for `blockUnknown` (under `authentication`) and whether the probe endpoint(s) require authentication:
-```
+```json
{
"name": "k8s-probe-0",
"role": null,
@@ -735,7 +737,7 @@ In this case, the `"role":null` indicates this endpoint allows anonymous access
The `"collection":null` value indicates the path is not associated with any collection, i.e. it is a top-level system path.
The operator sends GET requests to the `/admin/collections` endpoint to get cluster status to determine the rolling restart order:
-```
+```json
{
"name": "k8s-status",
"role": "k8s",
@@ -747,7 +749,7 @@ In this case, the `"role":"k8s"` indicates the requesting user must be in the `k
The Prometheus exporter sends GET requests to the `/admin/metrics` endpoint to collect metrics from each pod.
The exporter also hits the `/admin/ping` endpoint for every collection, which requires the following authorization rules:
-```
+```json
{
"name": "k8s-metrics",
"role": "k8s",
@@ -766,7 +768,7 @@ The `"collection":"*"` setting indicates this path applies to all collections, w
### Option 2: User-provided Basic Auth Secret
Alternatively, if users want full control over their cluster's security config, then they can provide a `kubernetes.io/basic-auth` secret containing the credentials for the user they want the operator to make API requests as:
-```
+```yaml
spec:
...
solrSecurity:
@@ -775,7 +777,7 @@ spec:
```
The supplied secret must be of type [Basic Authentication Secret](https://kubernetes.io/docs/concepts/configuration/secret/#basic-authentication-secret) and define both a `username` and `password`.
Here is an example of how to define a basic auth secret using YAML:
-```
+```yaml
apiVersion: v1
kind: Secret
metadata:
@@ -810,3 +812,23 @@ Also, changing the password for this user in the K8s secret will not update Solr
If you enable basic auth for your SolrCloud cluster, then you need to point the Prometheus exporter at the basic auth secret;
refer to [Prometheus Exporter with Basic Auth](../solr-prometheus-exporter/README.md#prometheus-exporter-with-basic-auth) for more details.
+
+## Various Runtime Parameters
+
+There are various runtime parameters that allow you to customize the running of your Solr Cloud via the Solr Operator.
+
+### Time to wait for Solr to be killed gracefully
+_Since v0.3.0_
+
+The Solr Operator manages the Solr StatefulSet in a way that when a Solr pod needs to be stopped, or deleted, Kubernetes and Solr are on the same page for how long to wait for the process to die gracefully.
+
+The default time given is 60 seconds, before Solr or Kubernetes tries to forcefully stop the Solr process.
+You can override this default with the field:
+
+```yaml
+spec:
+ ...
+ customSolrKubeOptions:
+ podOptions:
+ terminationGracePeriodSeconds: 120
+```
\ No newline at end of file
diff --git a/helm/solr-operator/crds/crds.yaml b/helm/solr-operator/crds/crds.yaml
index d8130ce..f1e3826 100644
--- a/helm/solr-operator/crds/crds.yaml
+++ b/helm/solr-operator/crds/crds.yaml
@@ -3558,6 +3558,11 @@ spec:
format: int32
type: integer
type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs to terminate gracefully.
+ format: int64
+ minimum: 10
+ type: integer
tolerations:
description: Tolerations to be added for the StatefulSet.
items:
@@ -8800,6 +8805,11 @@ spec:
format: int32
type: integer
type: object
+ terminationGracePeriodSeconds:
+ description: Optional duration in seconds the pod needs to terminate gracefully.
+ format: int64
+ minimum: 10
+ type: integer
tolerations:
description: Tolerations to be added for the StatefulSet.
items: