What is the difference between $container->get('current_user') and global $user? I've been looking at symfony's implementation of dependency injection, and it seems like a service locator pattern. 

It appears, at first blush, that the service container is not entirely different from a global namespace, and that any of the objects located within could be requested and modified in unexpected ways by some other module.  It seems like symfony has built in a way around these Action at a distance anti patterns by setting Scopes on the container, (addScope, enterScope, leaveScope), but I only see one example of addScope in CoreServiceProvider.php with a 'request' namespace.

Should module developers be encouraged to scope their interaction with the container if they plan on modifying services?
The general idea is to not use service location but define the dependencies directly in the container. There are edge cases where you need to pass along the full container, but really, try to avoid them. For objects like plugins and controllers we use a static factory pattern, on which you get the container to get your dependencies. Note: There aren't any objects which depend on those.

On top of that you also should avoid having to change services. As much as possible! Instead you should build a wrapper service which has a method like the \Drupal\Core\Session\AccountProxy ... you can set the current user on there
using setAccount.

  public function __construct(AccountInterface $current_user) {
    $this-&gt;currentUser = $current_user;
  }

  public function doSomething() {
    $this-&gt;currentUser-&gt;setAccount(new UserSession(...));
  }