Skip to content

Add option to disable Ryuk from code #3136

Closed

Description

@ksawerykarwacki

I know that there is a way to disable this with env variable. But for my scenario I don't need Ryuk to be spawn every time I run test containers (I have separate gradle tasks to setup and destroy containers which summons Ryuk when it is needed). Currently I have to use really janky hacks to inject env variable form code. Other option is to set env variable on every machine for our gradle build to work normally which is not ideal either.

For everyone who is wondering what is the scenario. You really don't want to spawn Oracle 20Gb container with Apex and Ords and wait minutes for db to load every time you want to recheck typo in your integration test. Instead we spin containers once at the start and than they run until clean task is called.

Activity

  1. bsideup commented on Aug 23, 2020

    @bsideup
    Member

    Have you considered the reusable containers feature introduced in #1781?

  2. asafm commented on Oct 22, 2020

    @asafm
    Contributor

    @bsideup I ran into another scenario recently answering to the same requirement: Turn off ryuk programmatically.
    The scenario was this: We have a Benchmark test, which spins up multiple virtual machines (EC2) that has docker installed on them (Linux machine) - one serves as client which bomards the other machine which serves as the server being tested. the benchmark test, which is a a normal JUnit, spins up both the client docker image on the client machine and the server docker image on the server machine using docker client, which communicates over tcp to the remote docker daemon. This all works well, but it's highly verbose code.

    I was trying out a new test, which uses GenericContainer which was much less verbose, but it failed on two reasons, but for clarity, I will focus in this ticket on the ryuk reason:
    When starting RYUK, the container starts successfully, then it tries to connect to it's exposed port, which is randomly selected. Since I'm communicating from the machine running the benchmark test (can it an EC2 machine or my laptop), to the machine running ryuk, it goes through a firewall dictates by Amazon Security Group. Since the port is random, I cant really set one up in the security group.
    Also, those server and client machines, are ephemeral - they are started in the beginning of the test and terminated when the test is done (it's quite rare to run those tests anyway since code is not changed that much), so we don't truly enjoy the benefit of ryuk, so no point in running it.

    For those two reasons, I wanted a way to programmatically, turn off ryuk. Couple of options come to mind:

    1. System Property - the most approachable option, and it doesn't require hacks as ENV var.
    2. Using the existing configuration framework Testcontainers uses today: TestcontainersConfiguration - I can set a file on the classpath of the benchmark test module and problem solved. They only issue with this is that it's not "programmatic".
    3. Like (2) but modify GenericContainer to accept a configuration, which will be used instead of TestcontainersConfiguration, thus programmatic, but I'm not sure yet how to do this, since a lot of the access to this class is via static access.

    WDYT?

    My current work-around is the same as was suggested: Pretty ugly reflections hack (taken from JUnit Jupiter to modify Env Vars using Reflection, and un-modify it when I'm done).

  3. bsideup commented on Oct 22, 2020

    @bsideup
    Member

    @asafm what you described made me thinking that, for this very exotic use case, the existing option (environment variable) should be enough. Env var isn't a hack, because disabled Ryuk is a property of an environment, not project.

    Ryuk (as well as the containers cleanup in general) is an important, essential part of Testcontainers. People are free to use the library the way they want to, but we don't want to provide an API that would allow doing bad things with the library. Even the environment variable to disable Ryuk was a bit of a trade off for exotic CI systems that are taking care of the cleanup themselves.

    Since I think that reusable containers may/will solve @ksawerykarwacki's case, I am closing this issue. There are (inconvenient for you ,but still) options for disabling Ryuk, and also some workarounds/hacks, which makes me think that you're not blocking.

    Providing a first class API to disable Ryuk would simply send a wrong message that we support disabling it. We don't :)

  4. asafm commented on Oct 22, 2020

    @asafm
    Contributor

    Another use case, is simply working with remote docker daemon instead of your own to reduce load on your laptop. We have a script which instead spinning up dockers which are must have for tests (base) locally, we spin up a remote EC2 machine, and spin the dockers there. When running tests, some spin up specific docker images using GenericContainers. When working locally all good, but when you switch to this mode, you are again forced to exit IntelliJ and start it again, just for environment variable to kick in.

    What am saying is that, environment can change, while working , be it locally, remote, etc. Having the option to set this disabled flag as part of the testcontainer config, or even a system property, would make it much easier to work with it.
    The other option is to use plain Docker-client and not enjoy the benefit of the Testcontainer DSL to communicate Docker Daemon.
    I think most people, the normal use case you're referring would hardly notice that extra option to disable it as System Property vs Env variable, as it would be called an Advance Setting. What I mean to say: It's not your public API as explicit as the Setters in GenericContainer or the a bit more hidden TestcontainersConfiguration. You have to dig deep in the code to know this option exists and then make a concious decision to turn it off, hence I think it's ok to not include it as API, thus still make 100% of users happy - the normal use case and the more exotic one, without sacrificing accidental misuse of this option, since it's not that public as the other configuration options are (I only mean this single addition of ability to set it via System Property).

    I respect your and the rest of the library maintainers opinion and decision, what ever you decide of course.

  5. kiview commented on Oct 22, 2020

    @kiview
    Member

    I agree with @bsideup that having an easily discoverable public API is a bit too much and a bit too potentially dangerous for normal users.

    However, I think @asafm idea of adding an additional configuration mechanism, e.g. System Property, is not too involved and seems more or less symmetric to the ENV approach to me, while still being more accessible from within the JVM.

  6. asafm commented on Oct 22, 2020

    @asafm
    Contributor

    Just to have TL; DR , the proposed change is:
    from:

            boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED"));
    

    to

            boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED"))
                                || !Boolean.parseBoolean((System.getProperty("TESTCONTAINERS_RYUK_DISABLED")));
    
  7. kiview commented on Oct 22, 2020

    @kiview
    Member

    Or rather

            boolean useRyuk = !Boolean.parseBoolean(System.getenv("TESTCONTAINERS_RYUK_DISABLED"))
                                || !Boolean.parseBoolean((System.getProperty("testcontainers.ryuk,disabled")));
    

    I assume ^^

  8. asafm commented on Oct 27, 2020

    @asafm
    Contributor

    @bsideup WDYT?

  9. bsideup commented on Oct 27, 2020

    @bsideup
    Member

    I would still not add it. If there is a UX problem with Ryuk (e.g. the random port, although every other container would have a random port, too) then we should fix it.

    IMO disabling Ryuk isn't how we should approach these UX issues.

    As a last resort, there are projects like https://stefanbirkner.github.io/system-rules/ in case you really need to disable it programmatically bypassing the measures that we added.

  10. asafm commented on Nov 3, 2020

    @asafm
    Contributor

    IMO both actions are valid: We can both fix the Ryuk UX of choosing a fixed port, and also allow the user to decide if they need to use RYUK, just like they configure any other feature they choose to use or not in Testcontainers.

    Regarding port - Is it o.k. from your side if I open a PR / Issue to have the port of ryuk optionally fixed and supply it as a configuration parameter? (e.g. testcontainers.properties file)?

    e.g. the random port, although every other container would have a random port, too

    That's not always the case. In my scenario, some containers have fixed port, from the same reason I stated before - I need to communicate from one container to the other, each on it's own EC2 machine, there for I have to know the port in advance to setup the firewall between them (i.e. Security Group rules).

    Regarding the disabling property of Ryuk: Your view is that terminating rouge containers started by Testcontainers - i.e. Ryuk - is an integral part of the system, in such a way that it's not configurable/optional other than per environment (i.e. environment variable).

    My view is a bit different: I "fell in love" with this library a very long time ago because it gave you this concise, non-verbose, API to Docker, with additional behaviors which are exactly what you need when you're using Docker for testing purposes. As time goes by, more and more behaviors have been added, which augment the way you work. All of them AFAIK have been optional to use, to fit your need, and configurable at runtime via properties / parameters.

    IMO, RYUK stands in contrast to this. It's another behavior added to the system, which is a must when running on shared build nodes, or your own laptop. Yet, there are cases - one-off build nodes for example, which don't require that behavior. The contrast here is that this behavior is non-configurable at runtime, only per environment (env vars). Fixing RYUK configuration to make it configurable via System Property or configuration file only aligns it with the other behaviors this library has added since @rnorth launched it.

  11. bsideup commented on Nov 6, 2020

    @bsideup
    Member

    Fixing RYUK configuration to make it configurable via System Property or configuration file only aligns it with the other behaviors this library has added since @rnorth launched it.

    Following @rnorth's vision was always the top priority for me :)

    And, given that, I would say that "What would Richard do" here is to e.g. communicate with Ryuk over stdin/stdout (aka the already established channel via Docker) instead of opening a separate TCP connection on a random port - and that's something I am already researching ;)

  12. asafm commented on Nov 16, 2020

    @asafm
    Contributor

    Sounds good. If you have an issue for that that I can watch , it will help me. Thanks @bsideup

  13. bsideup commented on Nov 24, 2020

    @bsideup
    Member

    @asafm I just submitted #3521 that uses docker exec instead of the TCP connection to Ryuk

  14. bsideup commented on Nov 27, 2020

    @bsideup
    Member

    @asafm any chance you can try #3521 in your environment? :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions