Brian,
In layman terms (and I’m sure some could consider this an over-simplification, as there are **much** more complex explanations to be had), the Lucee servlet is the “app" that runs within the servlet container, which is the “app" that runs within the “app" that is the JRE.
Your CFML code is the smallest “doll” in the Java Russian nesting doll, if you will. Each “doll” introduces shared language, classes and conventions along the way that the nested applications/servlets can take advantage of. You wouldn’t want those all in the language, itself, because their purposes, classes and conventions are not universal to all of the potential use-cases of the language.
This is not uncommon in any programming languages. Though they are not called such and differ in their implementation, NodeJS effectively functions as a “JRE" for Javascript, with each dependency in the chain (e.g. ExpressJS) becoming a “container” of sorts that introduces new language and conventions. Rails the same for Ruby - along with its framework ( aka - the Rails "container” ). PHP for the web requires a “container” in the form of FastCGI or some other middleware that can speak to a web server. Building apps with Go, Python, or any other language often requires (or is made easier by) the inclusion of “containers” along the way.
In short, Lucee introduces, via the JRE first and then the servlet container, the shared conventions through which a translation from CFML to the top-level language is possible. Without the nested “doll” the final step of translation is impossible.
HTH,
Jon