private void tryStart() {
        try {
            String dockerImageName = getDockerImageName();
            logger().debug("Starting container: {}", dockerImageName);

            Instant startedAt = Instant.now();
            logger().info("Creating container for image: {}", dockerImageName);
            CreateContainerCmd createCommand = dockerClient.createContainerCmd(dockerImageName);
            applyConfiguration(createCommand);

            createCommand.getLabels().putAll(DockerClientFactory.DEFAULT_LABELS);

            boolean reused = false;
            final boolean reusable;
            if (shouldBeReused) {
                if (!canBeReused()) {
                    throw new IllegalStateException("This container does not support reuse");
                }

                if (TestcontainersConfiguration.getInstance().environmentSupportsReuse()) {
                    createCommand
                        .getLabels()
                        .put(COPIED_FILES_HASH_LABEL, Long.toHexString(hashCopiedFiles().getValue()));

                    String hash = hash(createCommand);

                    containerId = findContainerForReuse(hash).orElse(null);

                    if (containerId != null) {
                        logger().info("Reusing container with ID: {} and hash: {}", containerId, hash);
                        reused = true;
                    } else {
                        logger().debug("Can't find a reusable running container with hash: {}", hash);

                        createCommand.getLabels().put(HASH_LABEL, hash);
                    }
                    reusable = true;
                } else {
                    logger()
                        .warn(
                            "" +
                            "Reuse was requested but the environment does not support the reuse of containers\n" +
                            "To enable reuse of containers, you must set 'testcontainers.reuse.enable=true' in a file located at {}",
                            Paths.get(System.getProperty("user.home"), ".testcontainers.properties")
                        );
                    reusable = false;
                }
            } else {
                reusable = false;
            }

            if (!reusable) {
                //noinspection deprecation
                createCommand = ResourceReaper.instance().register(this, createCommand);
            }

            if (!reused) {
                containerId = createCommand.exec().getId();

                // TODO use single "copy" invocation (and calculate an hash of the resulting tar archive)
                copyToFileContainerPathMap.forEach(this::copyFileToContainer);

                copyToTransferableContainerPathMap.forEach(this::copyFileToContainer);
            }

            connectToPortForwardingNetwork(createCommand.getNetworkMode());

            if (!reused) {
                containerIsCreated(containerId);

                logger().info("Container {} is starting: {}", dockerImageName, containerId);
                dockerClient.startContainerCmd(containerId).exec();
            } else {
                logger().info("Reusing existing container ({}) and not creating a new one", containerId);
            }

            // For all registered output consumers, start following as close to container startup as possible
            this.logConsumers.forEach(this::followOutput);

            // Wait until inspect container returns the mapped ports
            containerInfo =
                await()
                    .atMost(5, TimeUnit.SECONDS)
                    .pollInterval(DynamicPollInterval.ofMillis(50))
                    .pollInSameThread()
                    .until(
                        () -> dockerClient.inspectContainerCmd(containerId).exec(),
                        inspectContainerResponse -> {
                            Set<ExposedPort> exposedAndMappedPorts = inspectContainerResponse
                                .getNetworkSettings()
                                .getPorts()
                                .getBindings()
                                .entrySet()
                                .stream()
                                .filter(it -> Objects.nonNull(it.getValue())) // filter out exposed but not yet mapped
                                .map(Entry::getKey)
                                .collect(Collectors.toSet());

                            return exposedAndMappedPorts.containsAll(this.containerDef.getExposedPorts());
                        }
                    );

            String emulationWarning = checkForEmulation();
            if (emulationWarning != null) {
                logger().warn(emulationWarning);
            }

            // Tell subclasses that we're starting
            containerIsStarting(containerInfo, reused);

            // Wait until the container has reached the desired running state
            if (!this.startupCheckStrategy.waitUntilStartupSuccessful(this)) {
                // Bail out, don't wait for the port to start listening.
                // (Exception thrown here will be caught below and wrapped)
                throw new IllegalStateException("Container did not start correctly.");
            }

            // Wait until the process within the container has become ready for use (e.g. listening on network, log message emitted, etc).
            try {
                waitUntilContainerStarted();
            } catch (Exception e) {
                logger().debug("Wait strategy threw an exception", e);
                InspectContainerResponse inspectContainerResponse = null;
                try {
                    inspectContainerResponse = dockerClient.inspectContainerCmd(containerId).exec();
                } catch (NotFoundException notFoundException) {
                    logger().debug("Container {} not found", containerId, notFoundException);
                }

                if (inspectContainerResponse == null) {
                    throw new IllegalStateException("Wait strategy failed. Container is removed", e);
                }

                InspectContainerResponse.ContainerState state = inspectContainerResponse.getState();
                if (Boolean.TRUE.equals(state.getDead())) {
                    throw new IllegalStateException("Wait strategy failed. Container is dead", e);
                }

                if (Boolean.TRUE.equals(state.getOOMKilled())) {
                    throw new IllegalStateException(
                        "Wait strategy failed. Container crashed with out-of-memory (OOMKilled)",
                        e
                    );
                }

                String error = state.getError();
                if (!StringUtils.isBlank(error)) {
                    throw new IllegalStateException("Wait strategy failed. Container crashed: " + error, e);
                }

                if (!Boolean.TRUE.equals(state.getRunning())) {
                    throw new IllegalStateException(
                        "Wait strategy failed. Container exited with code " + state.getExitCode(),
                        e
                    );
                }

                throw e;
            }

            logger().info("Container {} started in {}", dockerImageName, Duration.between(startedAt, Instant.now()));
            containerIsStarted(containerInfo, reused);
        } catch (Exception e) {
            if (e instanceof UndeclaredThrowableException && e.getCause() instanceof Exception) {
                e = (Exception) e.getCause();
            }
            if (e instanceof InvocationTargetException && e.getCause() instanceof Exception) {
                e = (Exception) e.getCause();
            }
            logger().error("Could not start container", e);

            if (containerId != null) {
                // Log output if startup failed, either due to a container failure or exception (including timeout)
                final String containerLogs = getLogs();

                if (containerLogs.length() > 0) {
                    logger().error("Log output from the failed container:\n{}", getLogs());
                } else {
                    logger().error("There are no stdout/stderr logs available for the failed container");
                }
                stop();
            }

            throw new ContainerLaunchException("Could not create/start container", e);
        }
    }
Starts the container using docker, pulling an image if necessary.
core/src/main/java/org/testcontainers/containers/GenericContainer.java