I'm sure the following is a simplification, but it works for me.
An isolate is an independent copy of the V8 runtime, including a heap manager, a garbage collector, etc. Only one thread may access a given isolate at a time, but different threads may access different isolates simultaneously.
An isolate is not sufficient for running scripts, however. You also need a global (root) object. A context defines a complete script execution environment by designating an object in an isolate's heap as a global object.
Therefore, not only can many contexts "exist" in a given isolate, but they can also share any or all of their objects easily and safely. That's because their objects actually belong to the isolate and are protected by the isolate's exclusive lock.