Disable bootstrap checks for single-node discovery
While there are use-cases where a single-node is in production, there are also use-cases for starting a single-node that binds transport to an external interface where the node is not in production (for example, for testing the transport client against a node started in a Docker container). It's tricky to balance the desire to always enforce the bootstrap checks when a node might be in production with the need for the community to perform testing in situations that would trip the bootstrap checks. This commit enables some flexibility for these users. By setting the discovery type to "single-node", we disable the bootstrap checks independently of how transport is bound. While this sounds like a hole in the bootstrap checks, the bootstrap checks can already be avoided in the single-node use-case by binding only HTTP but not transport. For users that are genuinely in production on a single-node use-case with transport bound to an external use-case, they can set the system property "es.enable.bootstrap.checks" to force running the bootstrap checks. It would be a mistake for them not to do this. Relates #23598
This commit is contained in:
parent
c14be20744
commit
51b5dbffb7
|
@ -29,6 +29,7 @@ import org.elasticsearch.common.logging.Loggers;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.transport.BoundTransportAddress;
|
import org.elasticsearch.common.transport.BoundTransportAddress;
|
||||||
import org.elasticsearch.common.transport.TransportAddress;
|
import org.elasticsearch.common.transport.TransportAddress;
|
||||||
|
import org.elasticsearch.discovery.DiscoveryModule;
|
||||||
import org.elasticsearch.monitor.jvm.JvmInfo;
|
import org.elasticsearch.monitor.jvm.JvmInfo;
|
||||||
import org.elasticsearch.monitor.process.ProcessProbe;
|
import org.elasticsearch.monitor.process.ProcessProbe;
|
||||||
import org.elasticsearch.node.Node;
|
import org.elasticsearch.node.Node;
|
||||||
|
@ -73,7 +74,7 @@ final class BootstrapChecks {
|
||||||
final List<BootstrapCheck> combinedChecks = new ArrayList<>(builtInChecks);
|
final List<BootstrapCheck> combinedChecks = new ArrayList<>(builtInChecks);
|
||||||
combinedChecks.addAll(additionalChecks);
|
combinedChecks.addAll(additionalChecks);
|
||||||
check(
|
check(
|
||||||
enforceLimits(boundTransportAddress),
|
enforceLimits(boundTransportAddress, DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings)),
|
||||||
Collections.unmodifiableList(combinedChecks),
|
Collections.unmodifiableList(combinedChecks),
|
||||||
Node.NODE_NAME_SETTING.get(settings));
|
Node.NODE_NAME_SETTING.get(settings));
|
||||||
}
|
}
|
||||||
|
@ -166,11 +167,13 @@ final class BootstrapChecks {
|
||||||
* @param boundTransportAddress the node network bindings
|
* @param boundTransportAddress the node network bindings
|
||||||
* @return {@code true} if the checks should be enforced
|
* @return {@code true} if the checks should be enforced
|
||||||
*/
|
*/
|
||||||
static boolean enforceLimits(final BoundTransportAddress boundTransportAddress) {
|
static boolean enforceLimits(final BoundTransportAddress boundTransportAddress, final String discoveryType) {
|
||||||
Predicate<TransportAddress> isLoopbackOrLinkLocalAddress =
|
final Predicate<TransportAddress> isLoopbackOrLinkLocalAddress =
|
||||||
t -> t.address().getAddress().isLinkLocalAddress() || t.address().getAddress().isLoopbackAddress();
|
t -> t.address().getAddress().isLinkLocalAddress() || t.address().getAddress().isLoopbackAddress();
|
||||||
return !(Arrays.stream(boundTransportAddress.boundAddresses()).allMatch(isLoopbackOrLinkLocalAddress) &&
|
final boolean bound =
|
||||||
|
!(Arrays.stream(boundTransportAddress.boundAddresses()).allMatch(isLoopbackOrLinkLocalAddress) &&
|
||||||
isLoopbackOrLinkLocalAddress.test(boundTransportAddress.publishAddress()));
|
isLoopbackOrLinkLocalAddress.test(boundTransportAddress.publishAddress()));
|
||||||
|
return bound && !"single-node".equals(discoveryType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the list of checks to execute
|
// the list of checks to execute
|
||||||
|
|
|
@ -44,6 +44,7 @@ import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.CoreMatchers.equalTo;
|
import static org.hamcrest.CoreMatchers.equalTo;
|
||||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.hasToString;
|
import static org.hamcrest.Matchers.hasToString;
|
||||||
|
import static org.mockito.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||||
|
@ -98,7 +99,9 @@ public class BootstrapChecksTests extends ESTestCase {
|
||||||
when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0]));
|
when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0]));
|
||||||
when(boundTransportAddress.publishAddress()).thenReturn(publishAddress);
|
when(boundTransportAddress.publishAddress()).thenReturn(publishAddress);
|
||||||
|
|
||||||
assertTrue(BootstrapChecks.enforceLimits(boundTransportAddress));
|
final String discoveryType = randomFrom("zen", "single-node");
|
||||||
|
|
||||||
|
assertEquals(BootstrapChecks.enforceLimits(boundTransportAddress, discoveryType), !"single-node".equals(discoveryType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testEnforceLimitsWhenPublishingToNonLocalAddress() {
|
public void testEnforceLimitsWhenPublishingToNonLocalAddress() {
|
||||||
|
@ -114,7 +117,9 @@ public class BootstrapChecksTests extends ESTestCase {
|
||||||
when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0]));
|
when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0]));
|
||||||
when(boundTransportAddress.publishAddress()).thenReturn(publishAddress);
|
when(boundTransportAddress.publishAddress()).thenReturn(publishAddress);
|
||||||
|
|
||||||
assertTrue(BootstrapChecks.enforceLimits(boundTransportAddress));
|
final String discoveryType = randomFrom("zen", "single-node");
|
||||||
|
|
||||||
|
assertEquals(BootstrapChecks.enforceLimits(boundTransportAddress, discoveryType), !"single-node".equals(discoveryType));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testExceptionAggregation() {
|
public void testExceptionAggregation() {
|
||||||
|
|
|
@ -31,16 +31,31 @@ Elasticsearch instances must be reachable via transport communication so
|
||||||
they must bind transport to an external interface. Thus, we consider an
|
they must bind transport to an external interface. Thus, we consider an
|
||||||
Elasticsearch instance to be in development mode if it does not bind
|
Elasticsearch instance to be in development mode if it does not bind
|
||||||
transport to an external interface (the default), and is otherwise in
|
transport to an external interface (the default), and is otherwise in
|
||||||
production mode if it does bind transport to an external interface. Note
|
production mode if it does bind transport to an external interface.
|
||||||
that HTTP can be configured independently of transport via
|
|
||||||
|
Note that HTTP can be configured independently of transport via
|
||||||
<<modules-http,`http.host`>> and <<modules-transport,`transport.host`>>;
|
<<modules-http,`http.host`>> and <<modules-transport,`transport.host`>>;
|
||||||
this can be useful for configuring a single instance to be reachable via
|
this can be useful for configuring a single instance to be reachable via
|
||||||
HTTP for testing purposes without triggering production mode. If you do
|
HTTP for testing purposes without triggering production mode.
|
||||||
want to force enforcement of the bootstrap checks independent of the
|
|
||||||
binding of the transport protocal, you can set the system property
|
We recognize that some users need to bind transport to an external
|
||||||
`es.enforce.bootstrap.checks` to `true` (this can be useful on a
|
interface for testing their usage of the transport client. For this
|
||||||
single-node production system that does not bind transport to an external
|
situation, we provide the discovery type `single-node` (configure it by
|
||||||
interface).
|
setting `discovery.type` to `single-node`); in this situation, a node
|
||||||
|
will elect itself master and will not form a cluster with any other
|
||||||
|
node.
|
||||||
|
|
||||||
|
If you are running a single node in production, it is possible to evade
|
||||||
|
the bootstrap checks (either by not binding transport to an external
|
||||||
|
interface, or by binding transport to an external interface and setting
|
||||||
|
the discovery type to `single-node`). For this situation, you can force
|
||||||
|
execution of the bootstrap checks by setting the system property
|
||||||
|
`es.enforce.bootstrap.checks` to `true` (set this in <<jvm-options>>, or
|
||||||
|
by adding `-Des.enforce.bootstrap.checks=true` to the environment
|
||||||
|
variable `ES_JAVA_OPTS`). We strongly encourage you to do this if you
|
||||||
|
are in this specific situation. This system property can be used to
|
||||||
|
force execution of the bootstrap checks independent of the node
|
||||||
|
configuration.
|
||||||
|
|
||||||
=== Heap size check
|
=== Heap size check
|
||||||
|
|
||||||
|
@ -48,11 +63,11 @@ If a JVM is started with unequal initial and max heap size, it can be
|
||||||
prone to pauses as the JVM heap is resized during system usage. To avoid
|
prone to pauses as the JVM heap is resized during system usage. To avoid
|
||||||
these resize pauses, it's best to start the JVM with the initial heap
|
these resize pauses, it's best to start the JVM with the initial heap
|
||||||
size equal to the maximum heap size. Additionally, if
|
size equal to the maximum heap size. Additionally, if
|
||||||
<<bootstrap.memory_lock,`bootstrap.memory_lock`>> is enabled, the JVM will
|
<<bootstrap.memory_lock,`bootstrap.memory_lock`>> is enabled, the JVM
|
||||||
lock the initial size of the heap on startup. If the initial heap size
|
will lock the initial size of the heap on startup. If the initial heap
|
||||||
is not equal to the maximum heap size, after a resize it will not be the
|
size is not equal to the maximum heap size, after a resize it will not
|
||||||
case that all of the JVM heap is locked in memory. To pass the heap size
|
be the case that all of the JVM heap is locked in memory. To pass the
|
||||||
check, you must configure the <<heap-size,heap size>>.
|
heap size check, you must configure the <<heap-size,heap size>>.
|
||||||
|
|
||||||
|
|
||||||
=== File descriptor check
|
=== File descriptor check
|
||||||
|
@ -76,13 +91,13 @@ Elasticsearch would much rather use to service requests. There are
|
||||||
several ways to configure a system to disallow swapping. One way is by
|
several ways to configure a system to disallow swapping. One way is by
|
||||||
requesting the JVM to lock the heap in memory through `mlockall` (Unix)
|
requesting the JVM to lock the heap in memory through `mlockall` (Unix)
|
||||||
or virtual lock (Windows). This is done via the Elasticsearch setting
|
or virtual lock (Windows). This is done via the Elasticsearch setting
|
||||||
<<bootstrap.memory_lock,`bootstrap.memory_lock`>>. However, there are cases
|
<<bootstrap.memory_lock,`bootstrap.memory_lock`>>. However, there are
|
||||||
where this setting can be passed to Elasticsearch but Elasticsearch is
|
cases where this setting can be passed to Elasticsearch but
|
||||||
not able to lock the heap (e.g., if the `elasticsearch` user does not
|
Elasticsearch is not able to lock the heap (e.g., if the `elasticsearch`
|
||||||
have `memlock unlimited`). The memory lock check verifies that *if* the
|
user does not have `memlock unlimited`). The memory lock check verifies
|
||||||
`bootstrap.memory_lock` setting is enabled, that the JVM was successfully
|
that *if* the `bootstrap.memory_lock` setting is enabled, that the JVM
|
||||||
able to lock the heap. To pass the memory lock check, you might have to
|
was successfully able to lock the heap. To pass the memory lock check,
|
||||||
configure <<mlockall,`mlockall`>>.
|
you might have to configure <<mlockall,`mlockall`>>.
|
||||||
|
|
||||||
=== Maximum number of threads check
|
=== Maximum number of threads check
|
||||||
|
|
||||||
|
@ -139,29 +154,30 @@ the server VM.
|
||||||
|
|
||||||
=== Use serial collector check
|
=== Use serial collector check
|
||||||
|
|
||||||
There are various garbage collectors for the OpenJDK-derived JVMs targeting
|
There are various garbage collectors for the OpenJDK-derived JVMs
|
||||||
different workloads. The serial collector in particular is best suited for
|
targeting different workloads. The serial collector in particular is
|
||||||
single logical CPU machines or extremely small heaps, neither of which are
|
best suited for single logical CPU machines or extremely small heaps,
|
||||||
suitable for running Elasticsearch. Using the serial collector with
|
neither of which are suitable for running Elasticsearch. Using the
|
||||||
Elasticsearch can be devastating for performance. The serial collector check
|
serial collector with Elasticsearch can be devastating for performance.
|
||||||
ensures that Elasticsearch is not configured to run with the serial
|
The serial collector check ensures that Elasticsearch is not configured
|
||||||
collector. To pass the serial collector check, you must not start Elasticsearch
|
to run with the serial collector. To pass the serial collector check,
|
||||||
with the serial collector (whether it's from the defaults for the JVM that
|
you must not start Elasticsearch with the serial collector (whether it's
|
||||||
you're using, or you've explicitly specified it with `-XX:+UseSerialGC`). Note
|
from the defaults for the JVM that you're using, or you've explicitly
|
||||||
that the default JVM configuration that ship with Elasticsearch configures
|
specified it with `-XX:+UseSerialGC`). Note that the default JVM
|
||||||
Elasticsearch to use the CMS collector.
|
configuration that ship with Elasticsearch configures Elasticsearch to
|
||||||
|
use the CMS collector.
|
||||||
|
|
||||||
=== System call filter check
|
=== System call filter check
|
||||||
|
Elasticsearch installs system call filters of various flavors depending
|
||||||
Elasticsearch installs system call filters of various flavors depending on the
|
on the operating system (e.g., seccomp on Linux). These system call
|
||||||
operating system (e.g., seccomp on Linux). These system call filters are
|
filters are installed to prevent the ability to execute system calls
|
||||||
installed to prevent the ability to execute system calls related to forking as
|
related to forking as a defense mechanism against arbitrary code
|
||||||
a defense mechanism against arbitrary code execution attacks on Elasticsearch
|
execution attacks on Elasticsearch The system call filter check ensures
|
||||||
The system call filter check ensures that if system call filters are enabled,
|
that if system call filters are enabled, then they were successfully
|
||||||
then they were successfully installed. To pass the system call filter check you
|
installed. To pass the system call filter check you must either fix any
|
||||||
must either fix any configuration errors on your system that prevented system
|
configuration errors on your system that prevented system call filters
|
||||||
call filters from installing (check your logs), or *at your own risk* disable
|
from installing (check your logs), or *at your own risk* disable system
|
||||||
system call filters by setting `bootstrap.system_call_filter` to `false`.
|
call filters by setting `bootstrap.system_call_filter` to `false`.
|
||||||
|
|
||||||
=== OnError and OnOutOfMemoryError checks
|
=== OnError and OnOutOfMemoryError checks
|
||||||
|
|
||||||
|
@ -188,8 +204,8 @@ release build of the JVM.
|
||||||
|
|
||||||
=== G1GC check
|
=== G1GC check
|
||||||
|
|
||||||
Early versions of the HotSpot JVM that shipped with JDK 8 are known to have
|
Early versions of the HotSpot JVM that shipped with JDK 8 are known to
|
||||||
issues that can lead to index corruption when the G1GC collector is enabled.
|
have issues that can lead to index corruption when the G1GC collector is
|
||||||
The versions impacted are those earlier than the version of HotSpot that
|
enabled. The versions impacted are those earlier than the version of
|
||||||
shipped with JDK 8u40. The G1GC check detects these early versions of the
|
HotSpot that shipped with JDK 8u40. The G1GC check detects these early
|
||||||
HotSpot JVM.
|
versions of the HotSpot JVM.
|
||||||
|
|
Loading…
Reference in New Issue