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:
Jason Tedor 2017-04-04 09:39:04 -04:00 committed by GitHub
parent c14be20744
commit 51b5dbffb7
3 changed files with 76 additions and 52 deletions

View File

@ -29,6 +29,7 @@ import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.BoundTransportAddress;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.discovery.DiscoveryModule;
import org.elasticsearch.monitor.jvm.JvmInfo;
import org.elasticsearch.monitor.process.ProcessProbe;
import org.elasticsearch.node.Node;
@ -73,7 +74,7 @@ final class BootstrapChecks {
final List<BootstrapCheck> combinedChecks = new ArrayList<>(builtInChecks);
combinedChecks.addAll(additionalChecks);
check(
enforceLimits(boundTransportAddress),
enforceLimits(boundTransportAddress, DiscoveryModule.DISCOVERY_TYPE_SETTING.get(settings)),
Collections.unmodifiableList(combinedChecks),
Node.NODE_NAME_SETTING.get(settings));
}
@ -166,11 +167,13 @@ final class BootstrapChecks {
* @param boundTransportAddress the node network bindings
* @return {@code true} if the checks should be enforced
*/
static boolean enforceLimits(final BoundTransportAddress boundTransportAddress) {
Predicate<TransportAddress> isLoopbackOrLinkLocalAddress =
static boolean enforceLimits(final BoundTransportAddress boundTransportAddress, final String discoveryType) {
final Predicate<TransportAddress> isLoopbackOrLinkLocalAddress =
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()));
return bound && !"single-node".equals(discoveryType);
}
// the list of checks to execute

View File

@ -44,6 +44,7 @@ import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.Matchers.hasToString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
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.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() {
@ -114,7 +117,9 @@ public class BootstrapChecksTests extends ESTestCase {
when(boundTransportAddress.boundAddresses()).thenReturn(transportAddresses.toArray(new TransportAddress[0]));
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() {

View File

@ -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
Elasticsearch instance to be in development mode if it does not bind
transport to an external interface (the default), and is otherwise in
production mode if it does bind transport to an external interface. Note
that HTTP can be configured independently of transport via
production mode if it does bind transport to an external interface.
Note that HTTP can be configured independently of transport via
<<modules-http,`http.host`>> and <<modules-transport,`transport.host`>>;
this can be useful for configuring a single instance to be reachable via
HTTP for testing purposes without triggering production mode. If you do
want to force enforcement of the bootstrap checks independent of the
binding of the transport protocal, you can set the system property
`es.enforce.bootstrap.checks` to `true` (this can be useful on a
single-node production system that does not bind transport to an external
interface).
HTTP for testing purposes without triggering production mode.
We recognize that some users need to bind transport to an external
interface for testing their usage of the transport client. For this
situation, we provide the discovery type `single-node` (configure it by
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
@ -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
these resize pauses, it's best to start the JVM with the initial heap
size equal to the maximum heap size. Additionally, if
<<bootstrap.memory_lock,`bootstrap.memory_lock`>> is enabled, the JVM will
lock the initial size of the heap on startup. If the initial heap size
is not equal to the maximum heap size, after a resize it will not be the
case that all of the JVM heap is locked in memory. To pass the heap size
check, you must configure the <<heap-size,heap size>>.
<<bootstrap.memory_lock,`bootstrap.memory_lock`>> is enabled, the JVM
will lock the initial size of the heap on startup. If the initial heap
size is not equal to the maximum heap size, after a resize it will not
be the case that all of the JVM heap is locked in memory. To pass the
heap size check, you must configure the <<heap-size,heap size>>.
=== 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
requesting the JVM to lock the heap in memory through `mlockall` (Unix)
or virtual lock (Windows). This is done via the Elasticsearch setting
<<bootstrap.memory_lock,`bootstrap.memory_lock`>>. However, there are cases
where this setting can be passed to Elasticsearch but Elasticsearch is
not able to lock the heap (e.g., if the `elasticsearch` user does not
have `memlock unlimited`). The memory lock check verifies that *if* the
`bootstrap.memory_lock` setting is enabled, that the JVM was successfully
able to lock the heap. To pass the memory lock check, you might have to
configure <<mlockall,`mlockall`>>.
<<bootstrap.memory_lock,`bootstrap.memory_lock`>>. However, there are
cases where this setting can be passed to Elasticsearch but
Elasticsearch is not able to lock the heap (e.g., if the `elasticsearch`
user does not have `memlock unlimited`). The memory lock check verifies
that *if* the `bootstrap.memory_lock` setting is enabled, that the JVM
was successfully able to lock the heap. To pass the memory lock check,
you might have to configure <<mlockall,`mlockall`>>.
=== Maximum number of threads check
@ -139,29 +154,30 @@ the server VM.
=== Use serial collector check
There are various garbage collectors for the OpenJDK-derived JVMs targeting
different workloads. The serial collector in particular is best suited for
single logical CPU machines or extremely small heaps, neither of which are
suitable for running Elasticsearch. Using the serial collector with
Elasticsearch can be devastating for performance. The serial collector check
ensures that Elasticsearch is not configured to run with the serial
collector. To pass the serial collector check, you must not start Elasticsearch
with the serial collector (whether it's from the defaults for the JVM that
you're using, or you've explicitly specified it with `-XX:+UseSerialGC`). Note
that the default JVM configuration that ship with Elasticsearch configures
Elasticsearch to use the CMS collector.
There are various garbage collectors for the OpenJDK-derived JVMs
targeting different workloads. The serial collector in particular is
best suited for single logical CPU machines or extremely small heaps,
neither of which are suitable for running Elasticsearch. Using the
serial collector with Elasticsearch can be devastating for performance.
The serial collector check ensures that Elasticsearch is not configured
to run with the serial collector. To pass the serial collector check,
you must not start Elasticsearch with the serial collector (whether it's
from the defaults for the JVM that you're using, or you've explicitly
specified it with `-XX:+UseSerialGC`). Note that the default JVM
configuration that ship with Elasticsearch configures Elasticsearch to
use the CMS collector.
=== System call filter check
Elasticsearch installs system call filters of various flavors depending on the
operating system (e.g., seccomp on Linux). These system call filters are
installed to prevent the ability to execute system calls related to forking as
a defense mechanism against arbitrary code execution attacks on Elasticsearch
The system call filter check ensures that if system call filters are enabled,
then they were successfully installed. To pass the system call filter check you
must either fix any configuration errors on your system that prevented system
call filters from installing (check your logs), or *at your own risk* disable
system call filters by setting `bootstrap.system_call_filter` to `false`.
Elasticsearch installs system call filters of various flavors depending
on the operating system (e.g., seccomp on Linux). These system call
filters are installed to prevent the ability to execute system calls
related to forking as a defense mechanism against arbitrary code
execution attacks on Elasticsearch The system call filter check ensures
that if system call filters are enabled, then they were successfully
installed. To pass the system call filter check you must either fix any
configuration errors on your system that prevented system call filters
from installing (check your logs), or *at your own risk* disable system
call filters by setting `bootstrap.system_call_filter` to `false`.
=== OnError and OnOutOfMemoryError checks
@ -188,8 +204,8 @@ release build of the JVM.
=== G1GC check
Early versions of the HotSpot JVM that shipped with JDK 8 are known to have
issues that can lead to index corruption when the G1GC collector is enabled.
The versions impacted are those earlier than the version of HotSpot that
shipped with JDK 8u40. The G1GC check detects these early versions of the
HotSpot JVM.
Early versions of the HotSpot JVM that shipped with JDK 8 are known to
have issues that can lead to index corruption when the G1GC collector is
enabled. The versions impacted are those earlier than the version of
HotSpot that shipped with JDK 8u40. The G1GC check detects these early
versions of the HotSpot JVM.